<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">---

 /dev/null                              |    0 
 arch/alpha/Kconfig                     |   18 
 arch/arm/Kconfig                       |   18 
 arch/arm26/Kconfig                     |   18 
 arch/i386/Kconfig                      |   18 
 arch/ia64/Kconfig                      |   18 
 arch/m68knommu/Kconfig                 |   18 
 arch/mips/Kconfig                      |   18 
 arch/ppc/Kconfig                       |   18 
 arch/ppc64/Kconfig                     |   18 
 arch/sh/Kconfig                        |   18 
 arch/sparc64/Kconfig                   |   18 
 arch/v850/Kconfig                      |   18 
 arch/x86_64/Kconfig                    |   18 
 drivers/net/gt96100eth.c               |    6 
 drivers/parisc/Kconfig                 |   18 
 drivers/pci/hotplug/Kconfig            |   90 
 drivers/pci/hotplug/Makefile           |   40 
 drivers/pci/hotplug/pci_hotplug.h      |   21 
 drivers/pci/hotplug/pci_hotplug_core.c |    1 
 drivers/pci/hotplug/pciehp.h           |  386 ++++
 drivers/pci/hotplug/pciehp_core.c      |  707 +++++++
 drivers/pci/hotplug/pciehp_ctrl.c      | 2622 ++++++++++++++++++++++++++++
 drivers/pci/hotplug/pciehp_hpc.c       | 1436 +++++++++++++++
 drivers/pci/hotplug/pciehp_pci.c       |  834 +++++++++
 drivers/pci/hotplug/pciehp_sysfs.c     |  143 +
 drivers/pci/hotplug/pciehprm.h         |   53 
 drivers/pci/hotplug/pciehprm_acpi.c    | 1689 ++++++++++++++++++
 drivers/pci/hotplug/pciehprm_nonacpi.c |  498 +++++
 drivers/pci/hotplug/pciehprm_nonacpi.h |   56 
 drivers/pci/hotplug/rpadlpar.h         |   24 
 drivers/pci/hotplug/rpadlpar_core.c    |  343 +++
 drivers/pci/hotplug/rpadlpar_sysfs.c   |  151 +
 drivers/pci/hotplug/rpaphp.h           |  101 +
 drivers/pci/hotplug/rpaphp_core.c      |  948 ++++++++++
 drivers/pci/hotplug/rpaphp_pci.c       |   75 
 drivers/pci/hotplug/shpchp.h           |  467 +++++
 drivers/pci/hotplug/shpchp_core.c      |  704 +++++++
 drivers/pci/hotplug/shpchp_ctrl.c      | 3055 +++++++++++++++++++++++++++++++++
 drivers/pci/hotplug/shpchp_hpc.c       | 1608 +++++++++++++++++
 drivers/pci/hotplug/shpchp_pci.c       |  821 ++++++++
 drivers/pci/hotplug/shpchp_sysfs.c     |  143 +
 drivers/pci/hotplug/shpchprm.h         |   56 
 drivers/pci/hotplug/shpchprm_acpi.c    | 1694 ++++++++++++++++++
 drivers/pci/hotplug/shpchprm_legacy.c  |  474 +++++
 drivers/pci/hotplug/shpchprm_legacy.h  |  113 +
 drivers/pci/hotplug/shpchprm_nonacpi.c |  431 ++++
 drivers/pci/hotplug/shpchprm_nonacpi.h |   56 
 drivers/pci/msi.c                      |    6 
 drivers/pci/msi.h                      |    4 
 drivers/pci/pci.c                      |   94 -
 drivers/pci/quirks.c                   |    9 
 drivers/s390/Kconfig                   |   22 
 include/linux/pci.h                    |    2 
 include/linux/pci_ids.h                |   13 
 init/Kconfig                           |   19 
 56 files changed, 19922 insertions(+), 345 deletions(-)

diff -puN arch/alpha/Kconfig~bk-pci arch/alpha/Kconfig
--- 25/arch/alpha/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/alpha/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -569,24 +569,6 @@ config VERBOSE_MCHECK_ON
 source "drivers/pci/Kconfig"
 source "drivers/eisa/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 config SRM_ENV
diff -puN arch/arm26/Kconfig~bk-pci arch/arm26/Kconfig
--- 25/arch/arm26/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/arm26/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -118,24 +118,6 @@ config XIP_KERNEL
 	  Select this option to create a kernel that can be programed into
 	  the OS ROMs.
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 comment "At least one math emulation must be selected"
 
 config FPE_NWFPE
diff -puN arch/arm/Kconfig~bk-pci arch/arm/Kconfig
--- 25/arch/arm/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/arm/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -365,24 +365,6 @@ endif
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 comment "At least one math emulation must be selected"
diff -puN arch/i386/Kconfig~bk-pci arch/i386/Kconfig
--- 25/arch/i386/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/i386/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -1169,24 +1169,6 @@ config SCx200
 	  This support is also available as a module.  If compiled as a
 	  module, it will be called scx200.
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN arch/ia64/Kconfig~bk-pci arch/ia64/Kconfig
--- 25/arch/ia64/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/ia64/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -445,24 +445,6 @@ config PCI_DOMAINS
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	help
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pci/hotplug/Kconfig"
 
 source "drivers/pcmcia/Kconfig"
diff -puN arch/m68knommu/Kconfig~bk-pci arch/m68knommu/Kconfig
--- 25/arch/m68knommu/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/m68knommu/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -464,24 +464,6 @@ config COMEMPCI
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable device"
-	  ---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN arch/mips/Kconfig~bk-pci arch/mips/Kconfig
--- 25/arch/mips/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/mips/Kconfig	2004-02-19 23:22:41.000000000 -0800
@@ -1344,24 +1344,6 @@ config MCA
 config SBUS
 	bool
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN -L arch/mips/pci/pci-cobalt.c /dev/null /dev/null
diff -puN arch/ppc64/Kconfig~bk-pci arch/ppc64/Kconfig
--- 25/arch/ppc64/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/ppc64/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -227,24 +227,6 @@ source "fs/Kconfig.binfmt"
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN arch/ppc/Kconfig~bk-pci arch/ppc/Kconfig
--- 25/arch/ppc/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/ppc/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -978,24 +978,6 @@ config PCI_PERMEDIA
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 endmenu
diff -puN arch/sh/Kconfig~bk-pci arch/sh/Kconfig
--- 25/arch/sh/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/sh/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -609,24 +609,6 @@ source "arch/sh/drivers/pci/Kconfig"
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN arch/sparc64/Kconfig~bk-pci arch/sparc64/Kconfig
--- 25/arch/sparc64/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/sparc64/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -186,24 +186,6 @@ config SPARC64
 	  SPARC64 ports; its web page is available at
 	  &lt;http://www.ultralinux.org/&gt;.
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 # Global things across all Sun machines.
 config RWSEM_GENERIC_SPINLOCK
 	bool
diff -puN arch/v850/Kconfig~bk-pci arch/v850/Kconfig
--- 25/arch/v850/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/v850/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -236,24 +236,6 @@ menu "Bus options (PCI, PCMCIA, EISA, MC
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable device"
-	  ---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN arch/x86_64/Kconfig~bk-pci arch/x86_64/Kconfig
--- 25/arch/x86_64/Kconfig~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/arch/x86_64/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -348,24 +348,6 @@ config PCI_USE_VECTOR
 
 source "drivers/pci/Kconfig"
 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well-known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems, or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
 source "drivers/pcmcia/Kconfig"
 
 source "drivers/pci/hotplug/Kconfig"
diff -puN drivers/net/gt96100eth.c~bk-pci drivers/net/gt96100eth.c
--- 25/drivers/net/gt96100eth.c~bk-pci	2004-02-19 23:22:39.000000000 -0800
+++ 25-akpm/drivers/net/gt96100eth.c	2004-02-19 23:22:44.000000000 -0800
@@ -661,9 +661,9 @@ int gt96100_init_module(void)
 	pcibios_read_config_word(0, 0, PCI_VENDOR_ID, &amp;vendor_id);
 	pcibios_read_config_word(0, 0, PCI_DEVICE_ID, &amp;device_id);
     
-	if (vendor_id != PCI_VENDOR_ID_GALILEO ||
-	    (device_id != PCI_DEVICE_ID_GALILEO_GT96100 &amp;&amp;
-	     device_id != PCI_DEVICE_ID_GALILEO_GT96100A)) {
+	if (vendor_id != PCI_VENDOR_ID_MARVELL ||
+	    (device_id != PCI_DEVICE_ID_MARVELL_GT96100 &amp;&amp;
+	     device_id != PCI_DEVICE_ID_MARVELL_GT96100A)) {
 		printk(KERN_ERR __FILE__ ": GT96100 not found!\n");
 		return -ENODEV;
 	}
diff -puN drivers/parisc/Kconfig~bk-pci drivers/parisc/Kconfig
--- 25/drivers/parisc/Kconfig~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/parisc/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -143,24 +143,6 @@ config PDC_CHASSIS
 	  This has nothing to do with Chassis LCD and LED support.
 	  
 	  If unsure, say Y.
- 
-config HOTPLUG
-	bool "Support for hot-pluggable devices"
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
 
 source "drivers/pcmcia/Kconfig"
 
diff -puN drivers/pci/hotplug/Kconfig~bk-pci drivers/pci/hotplug/Kconfig
--- 25/drivers/pci/hotplug/Kconfig~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/hotplug/Kconfig	2004-02-19 23:22:44.000000000 -0800
@@ -122,5 +122,95 @@ config HOTPLUG_PCI_CPCI_GENERIC
 
 	  When in doubt, say N.
 
+config HOTPLUG_PCI_PCIE
+	tristate "PCI Express Hotplug driver"
+	depends on HOTPLUG_PCI
+	help
+	  Say Y here if you have a motherboard that supports PCI Express Native
+	  Hotplug
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pciehp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
+	bool "Use polling mechanism for hot-plug events."
+	depends on HOTPLUG_PCI_PCIE
+	help
+	  Say Y here if you want to use the polling mechanism for hot-plug 
+	  events.
+	   
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_PCIE_PHPRM_NONACPI
+	bool "Non-ACPI: Use $HPRT for resource/configuration"
+	depends on HOTPLUG_PCI_PCIE
+	help
+	  Say Y here if Hotplug resource/configuration information is provided
+	  by platform BIOS $HPRT or bridge resource information, not by ACPI.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC
+	tristate "SHPC PCI Hotplug driver"
+	depends on HOTPLUG_PCI
+	help
+	  Say Y here if you have a motherboard with a SHPC PCI Hotplug
+	  controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called shpchp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
+	bool "Use polling mechanism for hot-plug events"
+	depends on HOTPLUG_PCI_SHPC
+	help
+	  Say Y here if you want to use the polling mechanism for hot-plug 
+	  events.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC_PHPRM_NONACPI
+	bool "Non-ACPI: Use $HPRT for resource/configuration"
+	depends on HOTPLUG_PCI_SHPC
+	help
+	  Say Y here if Hotplug resource/configuration information is provided
+	  by platform BIOS $HPRT or bridge resource information, not by ACPI.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+	bool "For AMD SHPC only: Use $HRT for resource/configuration"
+	depends on HOTPLUG_PCI_SHPC &amp;&amp; HOTPLUG_PCI_SHPC_PHPRM_NONACPI
+	help
+	  Say Y here for AMD SHPC. You have to select this option if you are 
+	  using this driver on AMD platform with SHPC.
+
+config HOTPLUG_PCI_RPA
+	tristate "RPA PCI Hotplug driver"
+	depends on HOTPLUG_PCI &amp;&amp; PPC_PSERIES &amp;&amp; PPC64
+	help
+	  Say Y here if you have a a RPA system that supports PCI Hotplug.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rpaphp.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_RPA_DLPAR
+	tristate "RPA Dynamic Logical Partitioning for I/O slots"
+	depends on HOTPLUG_PCI_RPA
+	help
+	  Say Y here if your system supports Dynamic Logical Partitioning
+	  for I/O slots.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rpadlpar_io.
+ 
+ 	  When in doubt, say N.
+
 endmenu
 
diff -puN drivers/pci/hotplug/Makefile~bk-pci drivers/pci/hotplug/Makefile
--- 25/drivers/pci/hotplug/Makefile~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/hotplug/Makefile	2004-02-19 23:22:44.000000000 -0800
@@ -9,6 +9,10 @@ obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp
 obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
 obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550)	+= cpcihp_zt5550.o
 obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC)	+= cpcihp_generic.o
+obj-$(CONFIG_HOTPLUG_PCI_PCIE)		+= pciehp.o
+obj-$(CONFIG_HOTPLUG_PCI_SHPC)		+= shpchp.o
+obj-$(CONFIG_HOTPLUG_PCI_RPA)		+= rpaphp.o
+obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR)	+= rpadlpar_io.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o
 
@@ -33,6 +37,24 @@ acpiphp-objs		:=	acpiphp_core.o	\
 				acpiphp_pci.o	\
 				acpiphp_res.o
 
+rpaphp-objs		:=	rpaphp_core.o	\
+				rpaphp_pci.o	
+
+rpadlpar_io-objs	:=	rpadlpar_core.o \
+				rpadlpar_sysfs.o
+
+pciehp-objs		:=	pciehp_core.o	\
+				pciehp_ctrl.o	\
+				pciehp_pci.o	\
+				pciehp_sysfs.o	\
+				pciehp_hpc.o
+
+shpchp-objs		:=	shpchp_core.o	\
+				shpchp_ctrl.o	\
+				shpchp_pci.o	\
+				shpchp_sysfs.o	\
+				shpchp_hpc.o
+
 ifdef CONFIG_HOTPLUG_PCI_ACPI
   EXTRA_CFLAGS  += -D_LINUX -I$(TOPDIR)/drivers/acpi
   ifdef CONFIG_ACPI_DEBUG
@@ -43,3 +65,21 @@ endif
 ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
 	cpqphp-objs += cpqphp_nvram.o
 endif
+
+ifeq ($(CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI),y)
+  pciehp-objs += pciehprm_nonacpi.o
+else
+  pciehp-objs += pciehprm_acpi.o
+  EXTRA_CFLAGS  += -D_LINUX -I$(TOPDIR)/drivers/acpi -I$(TOPDIR)/drivers/acpi/include 
+endif
+
+ifeq ($(CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY),y)
+  shpchp-objs += shpchprm_legacy.o
+else
+   ifeq ($(CONFIG_HOTPLUG_PCI_SHPC_PHPRM_NONACPI),y)
+     shpchp-objs += shpchprm_nonacpi.o
+   else
+      shpchp-objs += shpchprm_acpi.o
+      EXTRA_CFLAGS  += -D_LINUX -I$(TOPDIR)/drivers/acpi 
+   endif
+endif
diff -puN /dev/null drivers/pci/hotplug/pciehp_core.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehp_core.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,707 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/miscdevice.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include "pciehp.h"
+#include "pciehprm.h"
+
+/* Global variables */
+int pciehp_debug;
+int pciehp_poll_mode;
+int pciehp_poll_time;
+struct controller *pciehp_ctrl_list;	/* = NULL */
+struct pci_func *pciehp_slot_list[256];
+
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Dan Zink &lt;dan.zink@compaq.com&gt;, Greg Kroah-Hartman &lt;greg@kroah.com&gt;, Dely Sy &lt;dely.l.sy@intel.com&gt;"
+#define DRIVER_DESC	"PCI Express Hot Plug Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(pciehp_debug, "i");
+MODULE_PARM(pciehp_poll_mode, "i");
+MODULE_PARM(pciehp_poll_time, "i");
+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");
+
+#define PCIE_MODULE_NAME "pciehp"
+
+static int pcie_start_thread (void);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =	get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+static int init_slots(struct controller *ctrl)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u32 slot_number;
+	int result;
+
+	dbg("%s\n",__FUNCTION__);
+
+	number_of_slots = ctrl-&gt;num_slots;
+	slot_device = ctrl-&gt;slot_device_offset;
+	slot_number = ctrl-&gt;first_slot;
+
+	while (number_of_slots) {
+		new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!new_slot)
+			return -ENOMEM;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot-&gt;hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!new_slot-&gt;hotplug_slot) {
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot-&gt;hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		new_slot-&gt;hotplug_slot-&gt;info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!new_slot-&gt;hotplug_slot-&gt;info) {
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot-&gt;hotplug_slot-&gt;info, 0, sizeof (struct hotplug_slot_info));
+		new_slot-&gt;hotplug_slot-&gt;name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!new_slot-&gt;hotplug_slot-&gt;name) {
+			kfree (new_slot-&gt;hotplug_slot-&gt;info);
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+
+		new_slot-&gt;magic = SLOT_MAGIC;
+		new_slot-&gt;ctrl = ctrl;
+		new_slot-&gt;bus = ctrl-&gt;slot_bus;
+		new_slot-&gt;device = slot_device;
+		new_slot-&gt;hpc_ops = ctrl-&gt;hpc_ops;
+
+		new_slot-&gt;number = ctrl-&gt;first_slot;
+		new_slot-&gt;hp_slot = slot_device - ctrl-&gt;slot_device_offset;
+
+		/* register this slot with the hotplug pci core */
+		new_slot-&gt;hotplug_slot-&gt;private = new_slot;
+		make_slot_name (new_slot-&gt;hotplug_slot-&gt;name, SLOT_NAME_SIZE, new_slot);
+		new_slot-&gt;hotplug_slot-&gt;ops = &amp;pciehp_hotplug_slot_ops;
+
+		new_slot-&gt;hpc_ops-&gt;get_power_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;power_status));
+		new_slot-&gt;hpc_ops-&gt;get_attention_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;attention_status));
+		new_slot-&gt;hpc_ops-&gt;get_latch_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;latch_status));
+		new_slot-&gt;hpc_ops-&gt;get_adapter_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;adapter_status));
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", 
+			new_slot-&gt;bus, new_slot-&gt;device, new_slot-&gt;hp_slot, new_slot-&gt;number, ctrl-&gt;slot_device_offset);
+		result = pci_hp_register (new_slot-&gt;hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot-&gt;hotplug_slot-&gt;info);
+			kfree (new_slot-&gt;hotplug_slot-&gt;name);
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return result;
+		}
+
+		new_slot-&gt;next = ctrl-&gt;slot;
+		ctrl-&gt;slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number += ctrl-&gt;slot_num_inc;
+	}
+
+	return(0);
+}
+
+
+static int cleanup_slots (struct controller * ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl-&gt;slot;
+	ctrl-&gt;slot = NULL;
+
+	while (old_slot) {
+		next_slot = old_slot-&gt;next;
+		pci_hp_deregister (old_slot-&gt;hotplug_slot);
+		kfree(old_slot-&gt;hotplug_slot-&gt;info);
+		kfree(old_slot-&gt;hotplug_slot-&gt;name);
+		kfree(old_slot-&gt;hotplug_slot);
+		kfree(old_slot);
+		old_slot = next_slot;
+	}
+
+
+	return(0);
+}
+
+static int get_ctlr_slot_config(struct controller *ctrl)
+{
+	int num_ctlr_slots;		/* Not needed; PCI Express has 1 slot per port*/
+	int first_device_num;		/* Not needed */
+	int physical_slot_num;
+	int updown;			/* Not needed */
+	int rc;
+	int flags;			/* Not needed */
+
+	rc = pcie_get_ctlr_slot_config(ctrl, &amp;num_ctlr_slots, &amp;first_device_num, &amp;physical_slot_num, &amp;updown, &amp;flags);
+	if (rc) {
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl-&gt;bus, ctrl-&gt;device);
+		return (-1);
+	}
+
+	ctrl-&gt;num_slots = num_ctlr_slots;	/* PCI Express has 1 slot per port */
+	ctrl-&gt;slot_device_offset = first_device_num;
+	ctrl-&gt;first_slot = physical_slot_num;
+	ctrl-&gt;slot_num_inc = updown; 	/* Not needed */		/* either -1 or 1 */
+
+	dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
+		__FUNCTION__, ctrl-&gt;slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, updown, 
+		ctrl-&gt;bus, ctrl-&gt;device);
+
+	return (0);
+}
+
+
+/*
+ * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	hotplug_slot-&gt;info-&gt;attention_status = status;
+	slot-&gt;hpc_ops-&gt;set_attention_status(slot, status);
+
+	return 0;
+}
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	return pciehp_enable_slot(slot);
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	return pciehp_disable_slot(slot);
+}
+
+
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	return 0;
+}
+
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_power_status(slot, value);
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;power_status;
+
+	return 0;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_attention_status(slot, value);
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;attention_status;
+
+	return 0;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_latch_status(slot, value);
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;latch_status;
+
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_adapter_status(slot, value);
+
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;adapter_status;
+
+	return 0;
+}
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+	
+	retval = slot-&gt;hpc_ops-&gt;get_max_bus_speed(slot, value);
+	if (retval &lt; 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+	
+	retval = slot-&gt;hpc_ops-&gt;get_cur_bus_speed(slot, value);
+	if (retval &lt; 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct controller *ctrl;
+	struct slot *t_slot;
+	int first_device_num = 0 ;	/* first PCI device number supported by this PCIE */  
+	int num_ctlr_slots;		/* number of slots supported by this HPC */
+	u8 value;
+
+	ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+	if (!ctrl) {
+		err("%s : out of memory\n", __FUNCTION__);
+		goto err_out_none;
+	}
+	memset(ctrl, 0, sizeof(struct controller));
+
+	dbg("%s: DRV_thread pid = %d\n", __FUNCTION__, current-&gt;pid);
+
+	rc = pcie_init(ctrl, pdev,
+		(php_intr_callback_t) pciehp_handle_attention_button,
+		(php_intr_callback_t) pciehp_handle_switch_change,
+		(php_intr_callback_t) pciehp_handle_presence_change,
+		(php_intr_callback_t) pciehp_handle_power_fault);
+	if (rc) {
+		dbg("%s: controller initialization failed\n", PCIE_MODULE_NAME);
+		goto err_out_free_ctrl;
+	}
+
+	ctrl-&gt;pci_dev = pdev;
+
+	pci_set_drvdata(pdev, ctrl);
+
+	ctrl-&gt;pci_bus = kmalloc (sizeof (*ctrl-&gt;pci_bus), GFP_KERNEL);
+	if (!ctrl-&gt;pci_bus) {
+		err("%s: out of memory\n", __FUNCTION__);
+		rc = -ENOMEM;
+		goto err_out_unmap_mmio_region;
+	}
+	dbg("%s: ctrl-&gt;pci_bus %p\n", __FUNCTION__, ctrl-&gt;pci_bus);
+	memcpy (ctrl-&gt;pci_bus, pdev-&gt;bus, sizeof (*ctrl-&gt;pci_bus));
+	ctrl-&gt;bus = pdev-&gt;bus-&gt;number;  /* ctrl bus */
+	ctrl-&gt;slot_bus = pdev-&gt;subordinate-&gt;number;  /* bus controlled by this HPC */
+
+	ctrl-&gt;device = PCI_SLOT(pdev-&gt;devfn);
+	ctrl-&gt;function = PCI_FUNC(pdev-&gt;devfn);
+	dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
+		ctrl-&gt;bus, ctrl-&gt;device, ctrl-&gt;function, pdev-&gt;irq);
+
+	/*
+	 *	Save configuration headers for this and subordinate PCI buses
+	 */
+
+	rc = get_ctlr_slot_config(ctrl);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_out_free_ctrl_bus;
+	}
+	first_device_num = ctrl-&gt;slot_device_offset;
+	num_ctlr_slots = ctrl-&gt;num_slots; 
+
+	/* Store PCI Config Space for all devices on this bus */
+	dbg("%s: Before calling pciehp_save_config, ctrl-&gt;bus %x,ctrl-&gt;slot_bus %x\n", 
+		__FUNCTION__,ctrl-&gt;bus, ctrl-&gt;slot_bus);
+	rc = pciehp_save_config(ctrl, ctrl-&gt;slot_bus, num_ctlr_slots, first_device_num);
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Get IO, memory, and IRQ resources for new devices */
+	rc = pciehprm_find_available_resources(ctrl);
+	ctrl-&gt;add_support = !rc;
+	
+	if (rc) {
+		dbg("pciehprm_find_available_resources = %#x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Setup the slot information structures */
+	rc = init_slots(ctrl);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		goto err_out_free_ctrl_slot;
+	}
+
+	t_slot = pciehp_find_slot(ctrl, first_device_num);
+	dbg("%s: t_slot %p\n", __FUNCTION__, t_slot);
+
+	/*	Finish setting up the hot plug ctrl device */
+	ctrl-&gt;next_event = 0;
+
+	if (!pciehp_ctrl_list) {
+		pciehp_ctrl_list = ctrl;
+		ctrl-&gt;next = NULL;
+	} else {
+		ctrl-&gt;next = pciehp_ctrl_list;
+		pciehp_ctrl_list = ctrl;
+	}
+
+	/* Wait for exclusive access to hardware */
+	down(&amp;ctrl-&gt;crit_sect);
+
+	t_slot-&gt;hpc_ops-&gt;get_adapter_status(t_slot, &amp;value); /* Check if slot is occupied */
+	dbg("%s: adpater value %x\n", __FUNCTION__, value);
+	if (!value) {
+		rc = t_slot-&gt;hpc_ops-&gt;power_off_slot(t_slot); /* Power off slot if not occupied*/
+		if (rc) {
+			/* Done with exclusive hardware access */
+			up(&amp;ctrl-&gt;crit_sect);
+			goto err_out_free_ctrl_slot;
+		} else
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+	}
+
+	/* Done with exclusive hardware access */
+	up(&amp;ctrl-&gt;crit_sect);
+
+	return 0;
+
+err_out_free_ctrl_slot:
+	cleanup_slots(ctrl);
+err_out_free_ctrl_bus:
+	kfree(ctrl-&gt;pci_bus);
+err_out_unmap_mmio_region:
+	ctrl-&gt;hpc_ops-&gt;release_ctlr(ctrl);
+err_out_free_ctrl:
+	kfree(ctrl);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static int pcie_start_thread(void)
+{
+	int loop;
+	int retval = 0;
+	
+	dbg("Initialize + Start the notification/polling mechanism \n");
+
+	retval = pciehp_event_start_thread();
+	if (retval) {
+		dbg("pciehp_event_start_thread() failed\n");
+		return retval;
+	}
+
+	dbg("Initialize slot lists\n");
+	/* One slot list for each bus in the system */
+	for (loop = 0; loop &lt; 256; loop++) {
+		pciehp_slot_list[loop] = NULL;
+	}
+
+	return retval;
+}
+
+
+static void unload_pciehpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	struct controller *ctrl;
+	struct controller *tctrl;
+	struct pci_resource *res;
+	struct pci_resource *tres;
+
+	ctrl = pciehp_ctrl_list;
+
+	while (ctrl) {
+		cleanup_slots(ctrl);
+
+		res = ctrl-&gt;io_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		res = ctrl-&gt;mem_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		res = ctrl-&gt;p_mem_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		res = ctrl-&gt;bus_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		kfree (ctrl-&gt;pci_bus);
+
+		ctrl-&gt;hpc_ops-&gt;release_ctlr(ctrl);
+
+		tctrl = ctrl;
+		ctrl = ctrl-&gt;next;
+
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop &lt; 256; loop++) {
+		next = pciehp_slot_list[loop];
+		while (next != NULL) {
+			res = next-&gt;io_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			res = next-&gt;mem_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			res = next-&gt;p_mem_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			res = next-&gt;bus_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			TempSlot = next;
+			next = next-&gt;next;
+			kfree(TempSlot);
+		}
+	}
+
+	/* Stop the notification mechanism */
+	pciehp_event_stop_thread();
+
+}
+
+
+static struct pci_device_id pcied_pci_tbl[] = {
+	{
+	.class =        ((PCI_CLASS_BRIDGE_PCI &lt;&lt; 8) | 0x00),
+	.class_mask =	~0,
+	.vendor =       PCI_ANY_ID,
+	.device =       PCI_ANY_ID,
+	.subvendor =    PCI_ANY_ID,
+	.subdevice =    PCI_ANY_ID,
+	},
+	
+	{ /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, pcied_pci_tbl);
+
+
+
+static struct pci_driver pcie_driver = {
+	.name		=	PCIE_MODULE_NAME,
+	.id_table	=	pcied_pci_tbl,
+	.probe		=	pcie_probe,
+	/* remove:	pcie_remove_one, */
+};
+
+
+
+static int __init pcied_init(void)
+{
+	int retval = 0;
+
+#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
+	pciehp_poll_mode = 1;
+#endif
+
+	retval = pcie_start_thread();
+	if (retval)
+		goto error_hpc_init;
+
+	retval = pciehprm_init(PCI);
+	if (!retval) {
+		retval = pci_module_init(&amp;pcie_driver);
+		dbg("pci_module_init = %d\n", retval);
+		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	}
+
+error_hpc_init:
+	if (retval) {
+		pciehprm_cleanup();
+		pciehp_event_stop_thread();
+	} else
+		pciehprm_print_pirt();
+
+	return retval;
+}
+
+static void __exit pcied_cleanup(void)
+{
+	dbg("unload_pciehpd()\n");
+	unload_pciehpd();
+
+	pciehprm_cleanup();
+
+	dbg("pci_unregister_driver\n");
+	pci_unregister_driver(&amp;pcie_driver);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+}
+
+
+module_init(pcied_init);
+module_exit(pcied_cleanup);
+
+
diff -puN /dev/null drivers/pci/hotplug/pciehp_ctrl.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehp_ctrl.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,2622 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/interrupt.h&gt;
+#include &lt;linux/delay.h&gt;
+#include &lt;linux/wait.h&gt;
+#include &lt;linux/smp_lock.h&gt;
+#include &lt;linux/pci.h&gt;
+#include "pciehp.h"
+#include "pciehprm.h"
+
+static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static int configure_new_function( struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+
+u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Attention Button Change */
+	dbg("pciehp:  Attention button interrupt received.\n");
+	
+	func = pciehp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread what to do */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+
+	/*
+	 *  Button pressed - See if need to TAKE ACTION!!!
+	 */
+	info("Button pressed on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+	taskInfo-&gt;event_type = INT_BUTTON_PRESS;
+
+	if ((p_slot-&gt;state == BLINKINGON_STATE)
+	    || (p_slot-&gt;state == BLINKINGOFF_STATE)) {
+		/* Cancel if we are still blinking; this means that we press the
+		 * attention again before the 5 sec. limit expires to cancel hot-add
+		 * or hot-remove
+		 */
+		taskInfo-&gt;event_type = INT_BUTTON_CANCEL;
+		info("Button cancel on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+	} else if ((p_slot-&gt;state == POWERON_STATE)
+		   || (p_slot-&gt;state == POWEROFF_STATE)) {
+		/* Ignore if the slot is on power-on or power-off state; this 
+		 * means that the previous attention button action to hot-add or
+		 * hot-remove is undergoing
+		 */
+		taskInfo-&gt;event_type = INT_BUTTON_IGNORE;
+		info("Button ignore on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+	}
+
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return 0;
+
+}
+
+u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Switch Change */
+	dbg("pciehp:  Switch interrupt received.\n");
+
+	func = pciehp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+
+	if (!getstatus) {
+		/*
+		 * Switch opened
+		 */
+		info("Latch open on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		func-&gt;switch_save = 0;
+		taskInfo-&gt;event_type = INT_SWITCH_OPEN;
+	} else {
+		/*
+		 *  Switch closed
+		 */
+		info("Latch close on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		func-&gt;switch_save = 0x10;
+		taskInfo-&gt;event_type = INT_SWITCH_CLOSE;
+	}
+
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Presence Change */
+	dbg("pciehp:  Presence/Notify input change.\n");
+
+	func = pciehp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	/* Switch is open, assume a presence change
+	 * Save the presence state
+	 */
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	if (func-&gt;presence_save) {
+		/*
+		 * Card Present
+		 */
+		taskInfo-&gt;event_type = INT_PRESENCE_ON;
+	} else {
+		/*
+		 * Not Present
+		 */
+		taskInfo-&gt;event_type = INT_PRESENCE_OFF;
+	}
+
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* power fault */
+	dbg("pciehp:  Power fault interrupt received.\n");
+
+	func = pciehp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* this is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	if ( !(p_slot-&gt;hpc_ops-&gt;query_power_fault(p_slot))) {
+		/*
+		 * power fault Cleared
+		 */
+		info("Power fault cleared on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		func-&gt;status = 0x00;
+		taskInfo-&gt;event_type = INT_POWER_FAULT_CLEAR;
+	} else {
+		/*
+		 *   power fault
+		 */
+		info("Power fault on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		taskInfo-&gt;event_type = INT_POWER_FAULT;
+		/* set power fault status for this board */
+		func-&gt;status = 0xFF;
+		info("power fault bit %x set\n", hp_slot);
+	}
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+
+/*
+ * sort_by_size
+ *
+ * Sorts nodes on the list by their length.
+ * Smallest first.
+ *
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)-&gt;next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)-&gt;next) &amp;&amp;
+		    ((*head)-&gt;length &gt; (*head)-&gt;next-&gt;length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)-&gt;next;
+			current_res-&gt;next = (*head)-&gt;next;
+			(*head)-&gt;next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res-&gt;next &amp;&amp; current_res-&gt;next-&gt;next) {
+			if (current_res-&gt;next-&gt;length &gt; current_res-&gt;next-&gt;next-&gt;length) {
+				out_of_order++;
+				next_res = current_res-&gt;next;
+				current_res-&gt;next = current_res-&gt;next-&gt;next;
+				current_res = current_res-&gt;next;
+				next_res-&gt;next = current_res-&gt;next;
+				current_res-&gt;next = next_res;
+			} else
+				current_res = current_res-&gt;next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * sort_by_max_size
+ *
+ * Sorts nodes on the list by their length.
+ * Largest first.
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)-&gt;next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)-&gt;next) &amp;&amp;
+		    ((*head)-&gt;length &lt; (*head)-&gt;next-&gt;length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)-&gt;next;
+			current_res-&gt;next = (*head)-&gt;next;
+			(*head)-&gt;next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res-&gt;next &amp;&amp; current_res-&gt;next-&gt;next) {
+			if (current_res-&gt;next-&gt;length &lt; current_res-&gt;next-&gt;next-&gt;length) {
+				out_of_order++;
+				next_res = current_res-&gt;next;
+				current_res-&gt;next = current_res-&gt;next-&gt;next;
+				current_res = current_res-&gt;next;
+				next_res-&gt;next = current_res-&gt;next;
+				current_res-&gt;next = next_res;
+			} else
+				current_res = current_res-&gt;next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * do_pre_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return(NULL);
+
+	rc = pciehp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	if ((*head)-&gt;base != (*orig_head)-&gt;base)
+		return(NULL);
+
+	if ((*head)-&gt;length == (*orig_head)-&gt;length)
+		return(NULL);
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 *  we may be able to split some off of the front
+	 */	
+	node = *head;
+
+	if (node-&gt;length &amp; (alignment -1)) {
+		/* this one isn't an aligned length, so we'll make a new entry
+		 * and split it up.
+		 */
+		split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!split_node)
+			return(NULL);
+
+		temp_dword = (node-&gt;length | (alignment-1)) + 1 - alignment;
+
+		split_node-&gt;base = node-&gt;base;
+		split_node-&gt;length = temp_dword;
+
+		node-&gt;length -= temp_dword;
+		node-&gt;base += split_node-&gt;length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node-&gt;next = node;
+	}
+
+	if (node-&gt;length &lt; alignment) {
+		return(NULL);
+	}
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node-&gt;next;
+		node-&gt;next = NULL;
+	} else {
+		prevnode = *head;
+		while (prevnode-&gt;next != node)
+			prevnode = prevnode-&gt;next;
+
+		prevnode-&gt;next = node-&gt;next;
+		node-&gt;next = NULL;
+	}
+
+	return(node);
+}
+
+
+/*
+ * do_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	rc = pciehp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	node = *head;
+
+	while (node-&gt;next) {
+		prevnode = node;
+		node = node-&gt;next;
+		kfree(prevnode);
+	}
+
+	if (node-&gt;length &lt; alignment) {
+		kfree(node);
+		return(NULL);
+	}
+
+	if (node-&gt;base &amp; (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node-&gt;base | (alignment-1)) + 1;
+		if ((node-&gt;length - (temp_dword - node-&gt;base)) &lt; alignment) {
+			kfree(node);
+			return(NULL);
+		}
+
+		node-&gt;length -= (temp_dword - node-&gt;base);
+		node-&gt;base = temp_dword;
+	}
+
+	if (node-&gt;length &amp; (alignment - 1)) {
+		/* There's stuff in use after this node */
+		kfree(node);
+		return(NULL);
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_io_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node = NULL;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( pciehp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node-&gt;next) {
+		if (node-&gt;length &lt; size)
+			continue;
+
+		if (node-&gt;base &amp; (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node-&gt;base | (size-1)) + 1;
+
+			/*/ Short circuit if adjusted size is too small */
+			if ((node-&gt;length - (temp_dword - node-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base;
+			split_node-&gt;length = temp_dword - node-&gt;base;
+			node-&gt;base = temp_dword;
+			node-&gt;length -= split_node-&gt;length;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node-&gt;length &gt; size) {
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base + size;
+			split_node-&gt;length = node-&gt;length - size;
+			node-&gt;length = size;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node-&gt;base &amp; 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size 
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node-&gt;next;
+		} else {
+			prevnode = *head;
+			while (prevnode-&gt;next != node)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = node-&gt;next;
+		}
+		node-&gt;next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_max_resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ * J.I. modified to put max size limits of; 64M-&gt;32M-&gt;16M-&gt;8M-&gt;4M-&gt;1M
+ *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
+ */
+static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
+	int i;
+
+	if (!(*head))
+		return(NULL);
+
+	if (pciehp_resource_sort_and_combine(head))
+		return(NULL);
+
+	if (sort_by_max_size(head))
+		return(NULL);
+
+	for (max = *head;max; max = max-&gt;next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max-&gt;length &lt; size)
+			continue;
+
+		if (max-&gt;base &amp; (size - 1)) {
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (max-&gt;base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max-&gt;length - (temp_dword - max-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = max-&gt;base;
+			split_node-&gt;length = temp_dword - max-&gt;base;
+			max-&gt;base = temp_dword;
+			max-&gt;length -= split_node-&gt;length;
+
+			/* Put it next in the list */
+			split_node-&gt;next = max-&gt;next;
+			max-&gt;next = split_node;
+		}
+
+		if ((max-&gt;base + max-&gt;length) &amp; (size - 1)) {
+			/* this one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+			temp_dword = ((max-&gt;base + max-&gt;length) &amp; ~(size - 1));
+			split_node-&gt;base = temp_dword;
+			split_node-&gt;length = max-&gt;length + max-&gt;base
+					     - split_node-&gt;base;
+			max-&gt;length -= split_node-&gt;length;
+
+			/* Put it in the list */
+			split_node-&gt;next = max-&gt;next;
+			max-&gt;next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max-&gt;length &lt; size)
+			continue;
+
+		for ( i = 0; max_size[i] &gt; size; i++) {
+			if (max-&gt;length &gt; max_size[i]) {
+				split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!split_node)
+					break;	/* return (NULL); */
+				split_node-&gt;base = max-&gt;base + max_size[i];
+				split_node-&gt;length = max-&gt;length - max_size[i];
+				max-&gt;length = max_size[i];
+				/* Put it next in the list */
+				split_node-&gt;next = max-&gt;next;
+				max-&gt;next = split_node;
+				break;
+			}
+		}
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max-&gt;next;
+		} else {
+			while (temp &amp;&amp; temp-&gt;next != max) {
+				temp = temp-&gt;next;
+			}
+
+			temp-&gt;next = max-&gt;next;
+		}
+
+		max-&gt;next = NULL;
+		return(max);
+	}
+
+	/* If we get here, we couldn't find one */
+	return(NULL);
+}
+
+
+/*
+ * get_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( pciehp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node-&gt;next) {
+		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
+		    __FUNCTION__, size, node, node-&gt;base, node-&gt;length);
+		if (node-&gt;length &lt; size)
+			continue;
+
+		if (node-&gt;base &amp; (size - 1)) {
+			dbg("%s: not aligned\n", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node-&gt;base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node-&gt;length - (temp_dword - node-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base;
+			split_node-&gt;length = temp_dword - node-&gt;base;
+			node-&gt;base = temp_dword;
+			node-&gt;length -= split_node-&gt;length;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node-&gt;length &gt; size) {
+			dbg("%s: too big\n", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base + size;
+			split_node-&gt;length = node-&gt;length - size;
+			node-&gt;length = size;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!\n", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node-&gt;next;
+		} else {
+			prevnode = *head;
+			while (prevnode-&gt;next != node)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = node-&gt;next;
+		}
+		node-&gt;next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return(node);
+}
+
+
+/*
+ * pciehp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int pciehp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return(1);
+
+	dbg("*head-&gt;next = %p\n",(*head)-&gt;next);
+
+	if (!(*head)-&gt;next)
+		return(0);	/* only one item on the list, already sorted! */
+
+	dbg("*head-&gt;base = 0x%x\n",(*head)-&gt;base);
+	dbg("*head-&gt;next-&gt;base = 0x%x\n",(*head)-&gt;next-&gt;base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)-&gt;next) &amp;&amp;
+		    ((*head)-&gt;base &gt; (*head)-&gt;next-&gt;base)) {
+			node1 = *head;
+			(*head) = (*head)-&gt;next;
+			node1-&gt;next = (*head)-&gt;next;
+			(*head)-&gt;next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1-&gt;next &amp;&amp; node1-&gt;next-&gt;next) {
+			if (node1-&gt;next-&gt;base &gt; node1-&gt;next-&gt;next-&gt;base) {
+				out_of_order++;
+				node2 = node1-&gt;next;
+				node1-&gt;next = node1-&gt;next-&gt;next;
+				node1 = node1-&gt;next;
+				node2-&gt;next = node1-&gt;next;
+				node1-&gt;next = node2;
+			} else
+				node1 = node1-&gt;next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 &amp;&amp; node1-&gt;next) {
+		if ((node1-&gt;base + node1-&gt;length) == node1-&gt;next-&gt;base) {
+			/* Combine */
+			dbg("8..\n");
+			node1-&gt;length += node1-&gt;next-&gt;length;
+			node2 = node1-&gt;next;
+			node1-&gt;next = node1-&gt;next-&gt;next;
+			kfree(node2);
+		} else
+			node1 = node1-&gt;next;
+	}
+
+	return(0);
+}
+
+
+/**
+ * pciehp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *pciehp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+	dbg("%s: busnumber %x\n", __FUNCTION__, busnumber);
+	new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+
+	if (new_slot == NULL) {
+		return(new_slot);
+	}
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot-&gt;next = NULL;
+	new_slot-&gt;configured = 1;
+
+	if (pciehp_slot_list[busnumber] == NULL) {
+		pciehp_slot_list[busnumber] = new_slot;
+	} else {
+		next = pciehp_slot_list[busnumber];
+		while (next-&gt;next != NULL)
+			next = next-&gt;next;
+		next-&gt;next = new_slot;
+	}
+	return(new_slot);
+}
+
+
+/*
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return(1);
+
+	next = pciehp_slot_list[old_slot-&gt;bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == old_slot) {
+		pciehp_slot_list[old_slot-&gt;bus] = old_slot-&gt;next;
+		pciehp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	}
+
+	while ((next-&gt;next != old_slot) &amp;&amp; (next-&gt;next != NULL)) {
+		next = next-&gt;next;
+	}
+
+	if (next-&gt;next == old_slot) {
+		next-&gt;next = old_slot-&gt;next;
+		pciehp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	if (bridge == NULL)
+		return(1);
+
+	secondaryBus = (bridge-&gt;config_space[0x06] &gt;&gt; 8) &amp; 0xFF;
+	subordinateBus = (bridge-&gt;config_space[0x06] &gt;&gt; 16) &amp; 0xFF;
+
+	for (tempBus = secondaryBus; tempBus &lt;= subordinateBus; tempBus++) {
+		next = pciehp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = pciehp_slot_list[tempBus];
+		}
+	}
+
+	next = pciehp_slot_list[bridge-&gt;bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == bridge) {
+		pciehp_slot_list[bridge-&gt;bus] = bridge-&gt;next;
+		kfree(bridge);
+		return(0);
+	}
+
+	while ((next-&gt;next != bridge) &amp;&amp; (next-&gt;next != NULL)) {
+		next = next-&gt;next;
+	}
+
+	if (next-&gt;next == bridge) {
+		next-&gt;next = bridge-&gt;next;
+		kfree(bridge);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * pciehp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *pciehp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = pciehp_slot_list[bus];
+	dbg("%s: bus %x device %x index %x\n",
+		__FUNCTION__, bus, device, index);
+	if (func != NULL) {
+		dbg("%s: func-&gt; bus %x device %x function %x pci_dev %p\n",
+			__FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function,
+			func-&gt;pci_dev);
+	} else
+		dbg("%s: func == NULL\n", __FUNCTION__);
+
+	if ((func == NULL) || ((func-&gt;device == device) &amp;&amp; (index == 0)))
+		return(func);
+
+	if (func-&gt;device == device)
+		found++;
+
+	while (func-&gt;next != NULL) {
+		func = func-&gt;next;
+
+		dbg("%s: In while loop, func-&gt; bus %x device %x function %x pci_dev %p\n",
+			__FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function,
+			func-&gt;pci_dev);
+		if (func-&gt;device == device)
+			found++;
+		dbg("%s: while loop, found %d, index %d\n", __FUNCTION__,
+			found, index);
+
+		if ((found == index) || (func-&gt;function == index)) {
+			dbg("%s: Found bus %x dev %x func %x\n", __FUNCTION__,
+					func-&gt;bus, func-&gt;device, func-&gt;function);
+			return(func);
+		}
+	}
+
+	return(NULL);
+}
+
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func-&gt;config_space[0x03] &gt;&gt; 16) &amp; 0xFF) == 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* The following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func * func, struct controller * ctrl)
+{
+	u8 hp_slot;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 retval, rc = 0;
+	struct pci_func *new_func = NULL;
+	struct slot *p_slot;
+	struct resource_lists res_lists;
+
+	p_slot = pciehp_find_slot(ctrl, func-&gt;device);
+	hp_slot = func-&gt;device - ctrl-&gt;slot_device_offset;
+
+	dbg("%s: func-&gt;device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func-&gt;device, ctrl-&gt;slot_device_offset, hp_slot);
+
+	/* Wait for exclusive access to hardware */
+	down(&amp;ctrl-&gt;crit_sect);
+
+	/* Power on slot */
+	rc = p_slot-&gt;hpc_ops-&gt;power_on_slot(p_slot);
+	if (rc)
+		return -1;
+
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+	
+	p_slot-&gt;hpc_ops-&gt;green_led_blink(p_slot);
+			
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&amp;ctrl-&gt;crit_sect);
+
+	/* Wait for ~1 second */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: afterlong_delay\n", __FUNCTION__);
+
+	/*  Make this to check for link training status */
+	rc = p_slot-&gt;hpc_ops-&gt;check_lnk_status(ctrl);  
+	if (rc) {
+		err("%s: Failed to check link status\n", __FUNCTION__);
+		return -1;
+	}
+
+	dbg("%s: func status = %x\n", __FUNCTION__, func-&gt;status);
+
+	/* Check for a power fault */
+	if (func-&gt;status == 0xFF) {
+		/* power fault occurred, but it was benign */
+		temp_register = 0xFFFFFFFF;
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
+		rc = POWER_FAILURE;
+		func-&gt;status = 0;
+	} else {
+		/* Get vendor/device ID u32 */
+		rc = pci_bus_read_config_dword (ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(func-&gt;device, func-&gt;function), 
+			PCI_VENDOR_ID, &amp;temp_register);
+		dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
+
+		if (rc != 0) {
+			/* Something's wrong here */
+			temp_register = 0xFFFFFFFF;
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
+		}
+		/* Preset return code.  It will be changed later if things go okay. */
+		rc = NO_ADAPTER_PRESENT;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl-&gt;io_head;
+		res_lists.mem_head = ctrl-&gt;mem_head;
+		res_lists.p_mem_head = ctrl-&gt;p_mem_head;
+		res_lists.bus_head = ctrl-&gt;bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &amp;res_lists, 0, 0);
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
+
+		ctrl-&gt;io_head = res_lists.io_head;
+		ctrl-&gt;mem_head = res_lists.mem_head;
+		ctrl-&gt;p_mem_head = res_lists.p_mem_head;
+		ctrl-&gt;bus_head = res_lists.bus_head;
+
+		pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;mem_head));
+		pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;p_mem_head));
+		pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;io_head));
+		pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;bus_head));
+
+		if (rc) {
+			/* Wait for exclusive access to hardware */
+			down(&amp;ctrl-&gt;crit_sect);
+
+			/* turn off slot, turn on Amber LED, turn off Green LED */
+			retval = p_slot-&gt;hpc_ops-&gt;power_off_slot(p_slot);   
+			/* In PCI Express, just power off slot */
+			if (retval) {
+				err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+
+			p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);   
+			
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+
+			/* turn on Amber LED */
+			retval = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);   
+			if (retval) {
+				err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&amp;ctrl-&gt;crit_sect);
+
+			return(rc);
+		}
+		pciehp_save_slot_config(ctrl, func);
+
+		func-&gt;status = 0;
+		func-&gt;switch_save = 0x10;
+		func-&gt;is_a_board = 0x01;
+
+		/* next, we will instantiate the linux pci_dev structures 
+		 * (with appropriate driver notification, if already present) 
+		 */
+		index = 0;
+		do {
+			new_func = pciehp_slot_find(ctrl-&gt;slot_bus, func-&gt;device, index++);
+			if (new_func &amp;&amp; !new_func-&gt;pci_dev) {
+				dbg("%s:call pci_hp_configure_dev, func %x\n", 
+					__FUNCTION__, index);
+				pciehp_configure_device(ctrl, new_func);
+			}
+		} while (new_func);
+
+		/* Wait for exclusive access to hardware */
+		down(&amp;ctrl-&gt;crit_sect);
+
+		p_slot-&gt;hpc_ops-&gt;green_led_on(p_slot);
+
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+
+	} else {
+		/* Wait for exclusive access to hardware */
+		down(&amp;ctrl-&gt;crit_sect);
+
+		/* turn off slot, turn on Amber LED, turn off Green LED */
+		retval = p_slot-&gt;hpc_ops-&gt;power_off_slot(p_slot);   
+		/* In PCI Express, just power off slot */
+		if (retval) {
+			err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+			return retval;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+		p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);   
+		
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+		/* turn on Amber LED */
+		retval = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);   
+		if (retval) {
+			err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+			return retval;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+
+		return(rc);
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+	struct slot *p_slot;
+
+	if (func == NULL)
+		return(1);
+
+	if (pciehp_unconfigure_device(func))
+		return(1);
+
+	device = func-&gt;device;
+
+	hp_slot = func-&gt;device - ctrl-&gt;slot_device_offset;
+	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	if ((ctrl-&gt;add_support) &amp;&amp;
+		!(func-&gt;bus_head || func-&gt;mem_head || func-&gt;p_mem_head || func-&gt;io_head)) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used.
+		 */
+		index = 0;
+
+		temp_func = func;
+
+		while ((temp_func = pciehp_slot_find(temp_func-&gt;bus, temp_func-&gt;device, index++))) {
+			if (temp_func-&gt;bus_head || temp_func-&gt;mem_head
+			    || temp_func-&gt;p_mem_head || temp_func-&gt;io_head) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip)
+			rc = pciehp_save_used_resources(ctrl, func, DISABLE_CARD);
+	}
+	/* Change status to shutdown */
+	if (func-&gt;is_a_board)
+		func-&gt;status = 0x01;
+	func-&gt;configured = 0;
+
+	/* Wait for exclusive access to hardware */
+	down(&amp;ctrl-&gt;crit_sect);
+
+	/* power off slot */
+	rc = p_slot-&gt;hpc_ops-&gt;power_off_slot(p_slot);
+	if (rc) {
+		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	/* turn off Green LED */
+	p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+	
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&amp;ctrl-&gt;crit_sect);
+
+	if (ctrl-&gt;add_support) {
+		while (func) {
+			res_lists.io_head = ctrl-&gt;io_head;
+			res_lists.mem_head = ctrl-&gt;mem_head;
+			res_lists.p_mem_head = ctrl-&gt;p_mem_head;
+			res_lists.bus_head = ctrl-&gt;bus_head;
+
+			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", 
+				func-&gt;bus, func-&gt;device, func-&gt;function);
+
+			pciehp_return_board_resources(func, &amp;res_lists);
+
+			ctrl-&gt;io_head = res_lists.io_head;
+			ctrl-&gt;mem_head = res_lists.mem_head;
+			ctrl-&gt;p_mem_head = res_lists.p_mem_head;
+			ctrl-&gt;bus_head = res_lists.bus_head;
+
+			pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;mem_head));
+			pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;p_mem_head));
+			pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;io_head));
+			pciehp_resource_sort_and_combine(&amp;(ctrl-&gt;bus_head));
+
+			if (is_bridge(func)) {
+				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl-&gt;seg, func-&gt;bus, func-&gt;device, func-&gt;function);
+				bridge_slot_remove(func);
+			} else
+				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", 
+					ctrl-&gt;seg, func-&gt;bus, func-&gt;device, func-&gt;function);
+				slot_remove(func);
+
+			func = pciehp_slot_find(ctrl-&gt;slot_bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = pciehp_slot_create(ctrl-&gt;slot_bus);
+
+		if (func == NULL) {
+			return(1);
+		}
+
+		func-&gt;bus = ctrl-&gt;slot_bus;
+		func-&gt;device = device;
+		func-&gt;function = 0;
+		func-&gt;configured = 0;
+		func-&gt;switch_save = 0x10;
+		func-&gt;is_a_board = 0;
+	}
+
+	return 0;
+}
+
+
+static void pushbutton_helper_thread (unsigned long data)
+{
+	pushbutton_pending = data;
+
+	up(&amp;event_semaphore);
+}
+
+
+/* this is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize("pciehpd_event");
+
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&amp;event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished || signal_pending(current))
+			break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			pciehp_pushbutton_thread(pushbutton_pending);
+		else
+			for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl-&gt;next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&amp;event_exit);
+	return 0;
+}
+
+int pciehp_event_start_thread (void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX_LOCKED(&amp;event_exit);
+	event_finished=0;
+
+	init_MUTEX_LOCKED(&amp;event_semaphore);
+	pid = kernel_thread(event_thread, 0, 0);
+
+	if (pid &lt; 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void pciehp_event_stop_thread (void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&amp;event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&amp;event_exit);
+}
+
+
+static int update_slot_info (struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	/* char buffer[SLOT_NAME_SIZE]; */
+	int result;
+
+	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	/* make_slot_name (&amp;buffer[0], SLOT_NAME_SIZE, slot); */
+
+	slot-&gt;hpc_ops-&gt;get_power_status(slot, &amp;(info-&gt;power_status));
+	slot-&gt;hpc_ops-&gt;get_attention_status(slot, &amp;(info-&gt;attention_status));
+	slot-&gt;hpc_ops-&gt;get_latch_status(slot, &amp;(info-&gt;latch_status));
+	slot-&gt;hpc_ops-&gt;get_adapter_status(slot, &amp;(info-&gt;adapter_status));
+
+	/* result = pci_hp_change_slot_info(buffer, info); */
+	result = pci_hp_change_slot_info(slot-&gt;hotplug_slot, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	u8 getstatus;
+	struct slot *p_slot;
+
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop &lt; 10; loop++) {
+			if (ctrl-&gt;event_queue[loop].event_type != 0) {
+				hp_slot = ctrl-&gt;event_queue[loop].hp_slot;
+
+				func = pciehp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+				p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+				dbg("hp_slot %d, func %p, p_slot %p\n", hp_slot, func, p_slot);
+
+				if (ctrl-&gt;event_queue[loop].event_type == INT_BUTTON_CANCEL) {
+					dbg("button cancel\n");
+					del_timer(&amp;p_slot-&gt;task_event);
+
+					switch (p_slot-&gt;state) {
+					case BLINKINGOFF_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&amp;ctrl-&gt;crit_sect);
+
+						p_slot-&gt;hpc_ops-&gt;green_led_on(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);
+						break;
+					case BLINKINGON_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&amp;ctrl-&gt;crit_sect);
+
+						p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);
+
+						break;
+					default:
+						warn("Not a valid state\n");
+						return;
+					}
+					info(msg_button_cancel, p_slot-&gt;number);
+					p_slot-&gt;state = STATIC_STATE;
+				}
+				/* ***********Button Pressed (No action on 1st press...) */
+				else if (ctrl-&gt;event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					dbg("Button pressed\n");
+
+					p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+					if (getstatus) {
+						/* slot is on */
+						dbg("slot is on\n");
+						p_slot-&gt;state = BLINKINGOFF_STATE;
+						info(msg_button_off, p_slot-&gt;number);
+					} else {
+						/* slot is off */
+						dbg("slot is off\n");
+						p_slot-&gt;state = BLINKINGON_STATE;
+						info(msg_button_on, p_slot-&gt;number);
+					}
+
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					/* blink green LED and turn off amber */
+					p_slot-&gt;hpc_ops-&gt;green_led_blink(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+					
+					p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+
+					init_timer(&amp;p_slot-&gt;task_event);
+					p_slot-&gt;task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+					p_slot-&gt;task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
+					p_slot-&gt;task_event.data = (unsigned long) p_slot;
+
+					dbg("add_timer p_slot = %p\n", (void *) p_slot);
+					add_timer(&amp;p_slot-&gt;task_event);
+				}
+				/***********POWER FAULT********************/
+				else if (ctrl-&gt;event_queue[loop].event_type == INT_POWER_FAULT) {
+					dbg("power fault\n");
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);
+					p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(p_slot);
+				}
+
+				ctrl-&gt;event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+
+	return;
+}
+
+
+/**
+ * pciehp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+void pciehp_pushbutton_thread (unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	int rc;
+	
+	pushbutton_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+	if (getstatus) {
+		p_slot-&gt;state = POWEROFF_STATE;
+		dbg("In power_down_board, b:d(%x:%x)\n", p_slot-&gt;bus, p_slot-&gt;device);
+
+		if (pciehp_disable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+			/* Turn on the Attention LED */
+			rc = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+	
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot-&gt;ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		}
+		p_slot-&gt;state = STATIC_STATE;
+	} else {
+		p_slot-&gt;state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot-&gt;bus, p_slot-&gt;device);
+
+		if (pciehp_enable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+			/* Turn off the green LED */
+			rc = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot-&gt;ctrl);
+			
+			p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot-&gt;ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		}
+		p_slot-&gt;state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+int pciehp_enable_slot (struct slot *p_slot)
+{
+	u8 getstatus = 0;
+	int rc;
+	struct pci_func *func;
+
+	func = pciehp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, 0);
+	if (!func) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return (1);
+	}
+
+	/* Check to see if (latch closed, card present, power off) */
+	down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+	rc = p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;getstatus);
+	if (rc || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	
+	rc = p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	if (rc || !getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	
+	rc = p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+	if (rc || getstatus) {
+		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+	slot_remove(func);
+
+	func = pciehp_slot_create(p_slot-&gt;bus);
+	if (func == NULL)
+		return (1);
+
+	func-&gt;bus = p_slot-&gt;bus;
+	func-&gt;device = p_slot-&gt;device;
+	func-&gt;function = 0;
+	func-&gt;configured = 0;
+	func-&gt;is_a_board = 1;
+
+	/* We have to save the presence info for these slots */
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	func-&gt;switch_save = !getstatus? 0x10:0;
+
+	rc = board_added(func, p_slot-&gt;ctrl);
+	if (rc) {
+		if (is_bridge(func))
+			bridge_slot_remove(func);
+		else
+			slot_remove(func);
+
+		/* Setup slot structure with entry for empty slot */
+		func = pciehp_slot_create(p_slot-&gt;bus);
+		if (func == NULL)
+			return (1);	/* Out of memory */
+
+		func-&gt;bus = p_slot-&gt;bus;
+		func-&gt;device = p_slot-&gt;device;
+		func-&gt;function = 0;
+		func-&gt;configured = 0;
+		func-&gt;is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+		p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+		func-&gt;switch_save = !getstatus? 0x10:0;
+	}
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+int pciehp_disable_slot (struct slot *p_slot)
+{
+	u8 class_code, header_type, BCR;
+	u8 index = 0;
+	u8 getstatus = 0;
+	u32 rc = 0;
+	int ret = 0;
+	unsigned int devfn;
+	struct pci_bus *pci_bus = p_slot-&gt;ctrl-&gt;pci_dev-&gt;subordinate;
+	struct pci_func *func;
+
+	if (!p_slot-&gt;ctrl)
+		return (1);
+
+	/* Check to see if (latch closed, card present, power on) */
+	down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+	ret = p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;getstatus);
+	if (ret || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+
+	ret = p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	if (ret || !getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+
+	ret = p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+	if (ret || !getstatus) {
+		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+	func = pciehp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, index++);
+
+	/* Make sure there are no video controllers here
+	 * for all func of p_slot
+	 */
+	while (func &amp;&amp; !rc) {
+		pci_bus-&gt;number = func-&gt;bus;
+		devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &amp;class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &amp;header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't supported */
+				if (BCR &amp; PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = pciehp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, index++);
+	}
+
+	func = pciehp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, 0);
+	if ((func != NULL) &amp;&amp; !rc) {
+		rc = remove_board(func, p_slot-&gt;ctrl);
+	} else if (!rc)
+		rc = 1;
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return(rc);
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+
+	/* Check for Multi-function device */
+	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func-&gt;device, func-&gt;function), 0x0E, &amp;temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte &amp; 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev);
+
+		if (rc) {
+			dbg("configure_new_function failed %d\n",rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = pciehp_slot_find(new_slot-&gt;bus, new_slot-&gt;device, index++);
+
+				if (new_slot)
+					pciehp_return_board_resources(new_slot, resources);
+			}
+
+			return(rc);
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/*  The following loop skips to the next present function
+		 *  and creates a board structure
+		 */
+
+		while ((function &lt; max_functions) &amp;&amp; (!stop_it)) {
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func-&gt;device, function), 0x00, &amp;ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = pciehp_slot_create(func-&gt;bus);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					return(1);
+				}
+
+				new_slot-&gt;bus = func-&gt;bus;
+				new_slot-&gt;device = func-&gt;device;
+				new_slot-&gt;function = function;
+				new_slot-&gt;is_a_board = 1;
+				new_slot-&gt;status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function &lt; max_functions);
+	dbg("returning from configure_new_device\n");
+
+	return 0;
+}
+
+
+/*
+ * Configuration logic that involves the hotplug data structures and 
+ * their bookkeeping
+ */
+
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int configure_new_function (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 device;
+	u8 class_code;
+	u16 temp_word;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct resource_lists temp_resources;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &amp;temp_byte);
+	if (rc)
+		return rc;
+	dbg("%s: bus %x dev %x func %x temp_byte = %x\n", __FUNCTION__,
+		func-&gt;bus, func-&gt;device, func-&gt;function, temp_byte);
+
+	if ((temp_byte &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		/* set Primary bus */
+		dbg("set Primary bus = 0x%x\n", func-&gt;bus);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func-&gt;bus);
+		if (rc)
+			return rc;
+
+		/* find range of busses to use */
+		bus_node = get_max_resource(&amp;resources-&gt;bus_head, 1L);
+
+		/* If we don't have any busses to allocate, we can't continue */
+		if (!bus_node) {
+			err("Got NO bus resource to use\n");
+			return -ENOMEM;
+		}
+		dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node-&gt;base, bus_node-&gt;length);
+
+		/* set Secondary bus */
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		dbg("func-&gt;bus %x\n", func-&gt;bus);
+
+		temp_byte = (u8)bus_node-&gt;base;
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate bus */
+		temp_byte = (u8)(bus_node-&gt;base + bus_node-&gt;length - 1);
+		dbg("set subordinate bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+		if (rc)
+			return rc;
+
+		/* Setup the IO, memory, and prefetchable windows */
+
+		io_node = get_max_resource(&amp;(resources-&gt;io_head), 0x1000L);
+		if (io_node) {
+			dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node-&gt;base, io_node-&gt;length, io_node-&gt;next);
+		}
+
+		mem_node = get_max_resource(&amp;(resources-&gt;mem_head), 0x100000L);
+		if (mem_node) {
+			dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node-&gt;base, mem_node-&gt;length, mem_node-&gt;next);
+		}
+
+		if (resources-&gt;p_mem_head)
+			p_mem_node = get_max_resource(&amp;(resources-&gt;p_mem_head), 0x100000L);
+		else {
+			/*
+			 * In some platform implementation, MEM and PMEM are not
+			 *  distinguished, and hence ACPI _CRS has only MEM entries
+			 *  for both MEM and PMEM.
+			 */
+			dbg("using MEM for PMEM\n");
+			p_mem_node = get_max_resource(&amp;(resources-&gt;mem_head), 0x100000L);
+		}
+		if (p_mem_node) {
+			dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node-&gt;base, p_mem_node-&gt;length, p_mem_node-&gt;next);
+		}
+
+		/* set up the IRQ info */
+		if (!resources-&gt;irqs) {
+			irqs.barber_pole = 0;
+			irqs.interrupt[0] = 0;
+			irqs.interrupt[1] = 0;
+			irqs.interrupt[2] = 0;
+			irqs.interrupt[3] = 0;
+			irqs.valid_INT = 0;
+		} else {
+			irqs.barber_pole = resources-&gt;irqs-&gt;barber_pole;
+			irqs.interrupt[0] = resources-&gt;irqs-&gt;interrupt[0];
+			irqs.interrupt[1] = resources-&gt;irqs-&gt;interrupt[1];
+			irqs.interrupt[2] = resources-&gt;irqs-&gt;interrupt[2];
+			irqs.interrupt[3] = resources-&gt;irqs-&gt;interrupt[3];
+			irqs.valid_INT = resources-&gt;irqs-&gt;valid_INT;
+		}
+
+		/* set up resource lists that are now aligned on top and bottom
+		 * for anything behind the bridge.
+		 */
+		temp_resources.bus_head = bus_node;
+		temp_resources.io_head = io_node;
+		temp_resources.mem_head = mem_node;
+		temp_resources.p_mem_head = p_mem_node;
+		temp_resources.irqs = &amp;irqs;
+
+		/* Make copies of the nodes we are going to pass down so that
+		 * if there is a problem,we can just use these to free resources
+		 */
+		hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+			if (hold_bus_node)
+				kfree(hold_bus_node);
+			if (hold_IO_node)
+				kfree(hold_IO_node);
+			if (hold_mem_node)
+				kfree(hold_mem_node);
+			if (hold_p_mem_node)
+				kfree(hold_p_mem_node);
+
+			return(1);
+		}
+
+		memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+		bus_node-&gt;base += 1;
+		bus_node-&gt;length -= 1;
+		bus_node-&gt;next = NULL;
+
+		/* If we have IO resources copy them and fill in the bridge's
+		 * IO range registers
+		 */
+		if (io_node) {
+			memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+			io_node-&gt;next = NULL;
+
+			/* set IO base and Limit registers */
+			RES_CHECK(io_node-&gt;base, 8);
+			temp_byte = (u8)(io_node-&gt;base &gt;&gt; 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			RES_CHECK(io_node-&gt;base + io_node-&gt;length - 1, 8);
+			temp_byte = (u8)((io_node-&gt;base + io_node-&gt;length - 1) &gt;&gt; 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+		} else {
+			kfree(hold_IO_node);
+			hold_IO_node = NULL;
+		}
+
+		/* If we have memory resources copy them and fill in the bridge's
+		 * memory range registers.  Otherwise, fill in the range
+		 * registers with values that disable them.
+		 */
+		if (mem_node) {
+			memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
+			mem_node-&gt;next = NULL;
+
+			/* set Mem base and Limit registers */
+			RES_CHECK(mem_node-&gt;base, 16);
+			temp_word = (u32)(mem_node-&gt;base &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			RES_CHECK(mem_node-&gt;base + mem_node-&gt;length - 1, 16);
+			temp_word = (u32)((mem_node-&gt;base + mem_node-&gt;length - 1) &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_mem_node);
+			hold_mem_node = NULL;
+		}
+
+		/* If we have prefetchable memory resources copy them and 
+		 * fill in the bridge's memory range registers.  Otherwise,
+		 * fill in the range registers with values that disable them.
+		 */
+		if (p_mem_node) {
+			memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
+			p_mem_node-&gt;next = NULL;
+
+			/* set Pre Mem base and Limit registers */
+			RES_CHECK(p_mem_node-&gt;base, 16);
+			temp_word = (u32)(p_mem_node-&gt;base &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			RES_CHECK(p_mem_node-&gt;base + p_mem_node-&gt;length - 1, 16);
+			temp_word = (u32)((p_mem_node-&gt;base + p_mem_node-&gt;length - 1) &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_p_mem_node);
+			hold_p_mem_node = NULL;
+		}
+
+		/* Adjust this to compensate for extra adjustment in first loop */
+		irqs.barber_pole--;
+
+		rc = 0;
+
+		/* Here we actually find the devices and configure them */
+		for (device = 0; (device &lt;= 0x1F) &amp;&amp; !rc; device++) {
+			irqs.barber_pole = (irqs.barber_pole + 1) &amp; 0x03;
+
+			ID = 0xFFFFFFFF;
+			pci_bus-&gt;number = hold_bus_node-&gt;base;
+			pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &amp;ID);
+			pci_bus-&gt;number = func-&gt;bus;
+
+			if (ID != 0xFFFFFFFF) {	  /*  device Present */
+				/* Setup slot structure. */
+				new_slot = pciehp_slot_create(hold_bus_node-&gt;base);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					rc = -ENOMEM;
+					continue;
+				}
+
+				new_slot-&gt;bus = hold_bus_node-&gt;base;
+				new_slot-&gt;device = device;
+				new_slot-&gt;function = 0;
+				new_slot-&gt;is_a_board = 1;
+				new_slot-&gt;status = 0;
+
+				rc = configure_new_device(ctrl, new_slot, 1, &amp;temp_resources, func-&gt;bus, func-&gt;device);
+				dbg("configure_new_device rc=0x%x\n",rc);
+			}	/* End of IF (device in slot?) */
+		}		/* End of FOR loop */
+
+		if (rc) {
+			pciehp_destroy_resource_list(&amp;temp_resources);
+
+			return_resource(&amp;(resources-&gt;bus_head), hold_bus_node);
+			return_resource(&amp;(resources-&gt;io_head), hold_IO_node);
+			return_resource(&amp;(resources-&gt;mem_head), hold_mem_node);
+			return_resource(&amp;(resources-&gt;p_mem_head), hold_p_mem_node);
+			return(rc);
+		}
+
+		/* save the interrupt routing information */
+		if (resources-&gt;irqs) {
+			resources-&gt;irqs-&gt;interrupt[0] = irqs.interrupt[0];
+			resources-&gt;irqs-&gt;interrupt[1] = irqs.interrupt[1];
+			resources-&gt;irqs-&gt;interrupt[2] = irqs.interrupt[2];
+			resources-&gt;irqs-&gt;interrupt[3] = irqs.interrupt[3];
+			resources-&gt;irqs-&gt;valid_INT = irqs.valid_INT;
+		} else if (!behind_bridge) {
+			/* We need to hook up the interrupts here */
+			for (cloop = 0; cloop &lt; 4; cloop++) {
+				if (irqs.valid_INT &amp; (0x01 &lt;&lt; cloop)) {
+					rc = pciehp_set_irq(func-&gt;bus, func-&gt;device,
+							   0x0A + cloop, irqs.interrupt[cloop]);
+					if (rc) {
+						pciehp_destroy_resource_list (&amp;temp_resources);
+						return_resource(&amp;(resources-&gt;bus_head), hold_bus_node);
+						return_resource(&amp;(resources-&gt;io_head), hold_IO_node);
+						return_resource(&amp;(resources-&gt;mem_head), hold_mem_node);
+						return_resource(&amp;(resources-&gt;p_mem_head), hold_p_mem_node);
+						return rc;
+					}
+				}
+			}	/* end of for loop */
+		}
+
+		/* Return unused bus resources
+		 * First use the temporary node to store information for the board
+		 */
+		if (hold_bus_node &amp;&amp; bus_node &amp;&amp; temp_resources.bus_head) {
+			hold_bus_node-&gt;length = bus_node-&gt;base - hold_bus_node-&gt;base;
+
+			hold_bus_node-&gt;next = func-&gt;bus_head;
+			func-&gt;bus_head = hold_bus_node;
+
+			temp_byte = (u8)(temp_resources.bus_head-&gt;base - 1);
+
+			/* set subordinate bus */
+			dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+			if (temp_resources.bus_head-&gt;length == 0) {
+				kfree(temp_resources.bus_head);
+				temp_resources.bus_head = NULL;
+			} else {
+				dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+					func-&gt;bus, func-&gt;device, temp_resources.bus_head-&gt;base, temp_resources.bus_head-&gt;length);
+				return_resource(&amp;(resources-&gt;bus_head), temp_resources.bus_head);
+			}
+		}
+
+		/* If we have IO space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_IO_node &amp;&amp; temp_resources.io_head) {
+			io_node = do_pre_bridge_resource_split(&amp;(temp_resources.io_head),
+							       &amp;hold_IO_node, 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				hold_IO_node-&gt;base = io_node-&gt;base + io_node-&gt;length;
+
+				RES_CHECK(hold_IO_node-&gt;base, 8);
+				temp_byte = (u8)((hold_IO_node-&gt;base) &gt;&gt; 8);
+				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+				return_resource(&amp;(resources-&gt;io_head), io_node);
+			}
+
+			io_node = do_bridge_resource_split(&amp;(temp_resources.io_head), 0x1000);
+
+			/*  Check if we were able to split something off */
+			if (io_node) {
+				/* First use the temporary node to store information for the board */
+				hold_IO_node-&gt;length = io_node-&gt;base - hold_IO_node-&gt;base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_IO_node-&gt;length) {
+					hold_IO_node-&gt;next = func-&gt;io_head;
+					func-&gt;io_head = hold_IO_node;
+
+					RES_CHECK(io_node-&gt;base - 1, 8);
+					temp_byte = (u8)((io_node-&gt;base - 1) &gt;&gt; 8);
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&amp;(resources-&gt;io_head), io_node);
+				} else {
+					/* it doesn't need any IO */
+					temp_byte = 0x00;
+					rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&amp;(resources-&gt;io_head), io_node);
+					kfree(hold_IO_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_IO_node-&gt;next = func-&gt;io_head;
+				func-&gt;io_head = hold_IO_node;
+			}
+		} else if (hold_IO_node) {
+			/* it used the whole range */
+			hold_IO_node-&gt;next = func-&gt;io_head;
+			func-&gt;io_head = hold_IO_node;
+		}
+
+		/* If we have memory space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_mem_node &amp;&amp; temp_resources.mem_head) {
+			mem_node = do_pre_bridge_resource_split(&amp;(temp_resources.mem_head), &amp;hold_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				hold_mem_node-&gt;base = mem_node-&gt;base + mem_node-&gt;length;
+
+				RES_CHECK(hold_mem_node-&gt;base, 16);
+				temp_word = (u32)((hold_mem_node-&gt;base) &gt;&gt; 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+				return_resource(&amp;(resources-&gt;mem_head), mem_node);
+			}
+
+			mem_node = do_bridge_resource_split(&amp;(temp_resources.mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_mem_node-&gt;length = mem_node-&gt;base - hold_mem_node-&gt;base;
+
+				if (hold_mem_node-&gt;length) {
+					hold_mem_node-&gt;next = func-&gt;mem_head;
+					func-&gt;mem_head = hold_mem_node;
+
+					/* configure end address */
+					RES_CHECK(mem_node-&gt;base - 1, 16);
+					temp_word = (u32)((mem_node-&gt;base - 1) &gt;&gt; 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					/* Return unused resources to the pool */
+					return_resource(&amp;(resources-&gt;mem_head), mem_node);
+				} else {
+					/* it doesn't need any Mem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					return_resource(&amp;(resources-&gt;mem_head), mem_node);
+					kfree(hold_mem_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_mem_node-&gt;next = func-&gt;mem_head;
+				func-&gt;mem_head = hold_mem_node;
+			}
+		} else if (hold_mem_node) {
+			/* it used the whole range */
+			hold_mem_node-&gt;next = func-&gt;mem_head;
+			func-&gt;mem_head = hold_mem_node;
+		}
+
+		/* If we have prefetchable memory space available and there is some 
+		 * left at the end, return the unused portion
+		 */
+		if (hold_p_mem_node &amp;&amp; temp_resources.p_mem_head) {
+			p_mem_node = do_pre_bridge_resource_split(&amp;(temp_resources.p_mem_head),
+								  &amp;hold_p_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				hold_p_mem_node-&gt;base = p_mem_node-&gt;base + p_mem_node-&gt;length;
+
+				RES_CHECK(hold_p_mem_node-&gt;base, 16);
+				temp_word = (u32)((hold_p_mem_node-&gt;base) &gt;&gt; 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+				return_resource(&amp;(resources-&gt;p_mem_head), p_mem_node);
+			}
+
+			p_mem_node = do_bridge_resource_split(&amp;(temp_resources.p_mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_p_mem_node-&gt;length = p_mem_node-&gt;base - hold_p_mem_node-&gt;base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_p_mem_node-&gt;length) {
+					hold_p_mem_node-&gt;next = func-&gt;p_mem_head;
+					func-&gt;p_mem_head = hold_p_mem_node;
+
+					RES_CHECK(p_mem_node-&gt;base - 1, 16);
+					temp_word = (u32)((p_mem_node-&gt;base - 1) &gt;&gt; 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&amp;(resources-&gt;p_mem_head), p_mem_node);
+				} else {
+					/* it doesn't need any PMem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&amp;(resources-&gt;p_mem_head), p_mem_node);
+					kfree(hold_p_mem_node);
+				}
+			} else {
+				/* it used the most of the range */
+				hold_p_mem_node-&gt;next = func-&gt;p_mem_head;
+				func-&gt;p_mem_head = hold_p_mem_node;
+			}
+		} else if (hold_p_mem_node) {
+			/* it used the whole range */
+			hold_p_mem_node-&gt;next = func-&gt;p_mem_head;
+			func-&gt;p_mem_head = hold_p_mem_node;
+		}
+
+		/* We should be configuring an IRQ and the bridge's base address
+		 * registers if it needs them.  Although we have never seen such
+		 * a device
+		 */
+
+		pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+		dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl-&gt;seg, func-&gt;bus, func-&gt;device, func-&gt;function);
+	} else if ((temp_byte &amp; 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		u64	base64;
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &amp;class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY)
+			return (DEVICE_TYPE_NOT_SUPPORTED);
+
+		/* Figure out IO and memory needs */
+		for (cloop = PCI_BASE_ADDRESS_0; cloop &lt;= PCI_BASE_ADDRESS_5; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &amp;temp_register);
+			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, 
+				func-&gt;bus, func-&gt;device, func-&gt;function);
+
+			if (!temp_register)
+				continue;
+
+			base64 = 0L;
+			if (temp_register &amp; PCI_BASE_ADDRESS_SPACE_IO) {
+				/* Map IO */
+
+				/* set base = amount of IO space */
+				base = temp_register &amp; 0xFFFFFFFC;
+				base = ~base + 1;
+
+				dbg("NEED IO length(0x%x)\n", base);
+				io_node = get_io_resource(&amp;(resources-&gt;io_head),(ulong)base);
+
+				/* allocate the resource to the board */
+				if (io_node) {
+					dbg("Got IO base=0x%x(length=0x%x)\n", io_node-&gt;base, io_node-&gt;length);
+					base = (u32)io_node-&gt;base;
+					io_node-&gt;next = func-&gt;io_head;
+					func-&gt;io_head = io_node;
+				} else {
+					err("Got NO IO resource(length=0x%x)\n", base);
+					return -ENOMEM;
+				}
+			} else {	/* map MEM */
+				int prefetchable = 1;
+				struct pci_resource **res_node = &amp;func-&gt;p_mem_head;
+				char *res_type_str = "PMEM";
+				u32	temp_register2;
+
+				if (!(temp_register &amp; PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+					prefetchable = 0;
+					res_node = &amp;func-&gt;mem_head;
+					res_type_str++;
+				}
+
+				base = temp_register &amp; 0xFFFFFFF0;
+				base = ~base + 1;
+
+				switch (temp_register &amp; PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+				case PCI_BASE_ADDRESS_MEM_TYPE_32:
+					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
+
+					if (prefetchable &amp;&amp; resources-&gt;p_mem_head)
+						mem_node=get_resource(&amp;(resources-&gt;p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node=get_resource(&amp;(resources-&gt;mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base = (u32)mem_node-&gt;base; 
+						mem_node-&gt;next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node-&gt;base, 
+							mem_node-&gt;length);
+					} else {
+						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				case PCI_BASE_ADDRESS_MEM_TYPE_64:
+					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &amp;temp_register2);
+					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, 
+						temp_register, base);
+
+					if (prefetchable &amp;&amp; resources-&gt;p_mem_head)
+						mem_node = get_resource(&amp;(resources-&gt;p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&amp;(resources-&gt;mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base64 = mem_node-&gt;base; 
+						mem_node-&gt;next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 &gt;&gt; 32), 
+							(u32)base64, mem_node-&gt;length);
+					} else {
+						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				default:
+					dbg("reserved BAR type=0x%x\n", temp_register);
+					break;
+				}
+
+			}
+
+			if (base64) {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+				cloop += 4;
+				base64 &gt;&gt;= 32;
+
+				if (base64) {
+					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
+					base64 = 0x0L;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+			} else {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+			}
+		}		/* End of base register loop */
+
+		/* disable ROM base Address */
+		temp_word = 0x00L;
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word);
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+		if (rc)
+			return rc;
+
+		pciehprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+
+		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl-&gt;seg, func-&gt;bus, func-&gt;device, 
+			func-&gt;function);
+	}  /* End of Not-A-Bridge else */
+	else {
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return(DEVICE_TYPE_NOT_SUPPORTED);
+	}
+
+	func-&gt;configured = 1;
+
+	return 0;
+}
+
diff -puN /dev/null drivers/pci/hotplug/pciehp.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehp.h	2004-02-19 23:22:44.000000000 -0800
@@ -0,0 +1,386 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+#ifndef _PCIEHP_H
+#define _PCIEHP_H
+
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;asm/semaphore.h&gt;
+#include &lt;asm/io.h&gt;		
+#include "pci_hotplug.h"
+
+#if !defined(CONFIG_HOTPLUG_PCI_PCIE_MODULE)
+	#define MY_NAME	"pciehp"
+#else
+	#define MY_NAME	THIS_MODULE-&gt;name
+#endif
+
+extern int pciehp_poll_mode;
+extern int pciehp_poll_time;
+extern int pciehp_debug;
+
+/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
+#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev* pci_dev;
+};
+
+#define SLOT_MAGIC	0x67267321
+struct slot {
+	u32 magic;
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u32 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	struct hpc_ops *hpc_ops;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head	slot_list;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void * hpc_ctlr_handle;		/* HPC controller handle */
+	int num_slots;			/* Number of slots on ctlr */
+	int slot_num_inc;			/* 1 or -1 */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	struct hpc_ops *hpc_ops;
+	wait_queue_head_t queue;	/* sleep &amp; wake process */
+	u8 next_event;
+	u8 seg;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 rev;
+	u8 slot_device_offset;
+	u8 add_support;
+	enum pci_bus_speed speed;
+	u32 first_slot;		/* First physical slot number */  /* PCIE only has 1 slot */
+	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
+	u8 push_flag;
+	u16 ctlrcap;
+	u16 vendor_id;
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+/* Error messages */
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define WRONG_BUS_FREQUENCY		0x0000000D
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+#define DISABLE_CARD			1
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_pcie	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"This system is not supported by this version of pciephd mdoule. Upgrade to a newer version of pciehpd\n"
+#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+/* sysfs function for the hotplug controller info */
+extern void pciehp_create_ctrl_files	(struct controller *ctrl);
+
+/* controller functions */
+extern void	pciehp_pushbutton_thread		(unsigned long event_pointer);
+extern int	pciehprm_find_available_resources	(struct controller *ctrl);
+extern int	pciehp_event_start_thread	(void);
+extern void	pciehp_event_stop_thread	(void);
+extern struct 	pci_func *pciehp_slot_create	(unsigned char busnumber);
+extern struct 	pci_func *pciehp_slot_find	(unsigned char bus, unsigned char device, unsigned char index);
+extern int	pciehp_enable_slot		(struct slot *slot);
+extern int	pciehp_disable_slot		(struct slot *slot);
+
+extern u8	pciehp_handle_attention_button	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_switch_change	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_presence_change	(u8 hp_slot, void *inst_id);
+extern u8	pciehp_handle_power_fault	(u8 hp_slot, void *inst_id);
+/* extern void	long_delay (int delay); */
+
+/* resource functions */
+extern int	pciehp_resource_sort_and_combine	(struct pci_resource **head);
+
+/* pci functions */
+extern int	pciehp_set_irq			(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+/*extern int	pciehp_get_bus_dev		(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
+extern int	pciehp_save_config	 	(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
+extern int	pciehp_save_used_resources	(struct controller *ctrl, struct pci_func * func, int flag);
+extern int	pciehp_save_slot_config		(struct controller *ctrl, struct pci_func * new_slot);
+extern void	pciehp_destroy_board_resources	(struct pci_func * func);
+extern int	pciehp_return_board_resources	(struct pci_func * func, struct resource_lists * resources);
+extern void	pciehp_destroy_resource_list	(struct resource_lists * resources);
+extern int	pciehp_configure_device		(struct controller* ctrl, struct pci_func* func);
+extern int	pciehp_unconfigure_device	(struct pci_func* func);
+
+
+/* Global variables */
+extern struct controller *pciehp_ctrl_list;
+extern struct pci_func *pciehp_slot_list[256];
+
+/* Inline functions */
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot-&gt;magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot-&gt;hotplug_slot) {
+		dbg("%s - slot-&gt;hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot-&gt;private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+static inline struct slot *pciehp_find_slot (struct controller *ctrl, u8 device)
+{
+	struct slot *p_slot, *tmp_slot = NULL;
+
+	if (!ctrl)
+		return NULL;
+
+	p_slot = ctrl-&gt;slot;
+
+	dbg("p_slot = %p\n", p_slot);
+
+	while (p_slot &amp;&amp; (p_slot-&gt;device != device)) {
+		tmp_slot = p_slot;
+		p_slot = p_slot-&gt;next;
+		dbg("In while loop, p_slot = %p\n", p_slot);
+	}
+	if (p_slot == NULL) {
+		err("ERROR: pciehp_find_slot device=0x%x\n", device);
+		p_slot = tmp_slot;
+	}
+
+	return (p_slot);
+}
+
+static inline int wait_for_ctrl_irq (struct controller *ctrl)
+{
+	int retval = 0;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	dbg("%s : start\n", __FUNCTION__);
+	add_wait_queue(&amp;ctrl-&gt;queue, &amp;wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	if (!pciehp_poll_mode) {
+		/* Sleep for up to 1 second */
+		schedule_timeout(1*HZ);
+	} else
+		schedule_timeout(2.5*HZ);
+	
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&amp;ctrl-&gt;queue, &amp;wait);
+	if (signal_pending(current))
+		retval =  -EINTR;
+
+	dbg("%s : end\n", __FUNCTION__);
+	return retval;
+}
+
+/* Puts node back in the resource list pointed to by head */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node-&gt;next = *head;
+	*head = node;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot-&gt;number);
+}
+
+enum php_ctlr_type {
+	PCI,
+	ISA,
+	ACPI
+};
+
+typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
+
+int pcie_init( struct controller *ctrl, struct pci_dev *pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback);
+
+
+/* This has no meaning for PCI Express, as there is only 1 slot per port */
+int pcie_get_ctlr_slot_config( struct controller *ctrl,
+		int *num_ctlr_slots,
+		int *first_device_num,
+		int *physical_slot_num,
+		int *updown,
+		int *flags);
+
+struct hpc_ops {
+	int	(*power_on_slot )		(struct slot *slot);
+	int	(*power_off_slot )		(struct slot *slot);
+	int	(*get_power_status)		(struct slot *slot, u8 *status);
+	int	(*get_attention_status)	(struct slot *slot, u8 *status);
+	int	(*set_attention_status)	(struct slot *slot, u8 status);
+	int	(*get_latch_status)		(struct slot *slot, u8 *status);
+	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
+
+	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+
+	int	(*get_max_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
+	int	(*get_cur_lnk_width)	(struct slot *slot, enum pcie_link_width *value);
+	
+	int	(*query_power_fault)	(struct slot *slot);
+	void	(*green_led_on)		(struct slot *slot);
+	void	(*green_led_off)	(struct slot *slot);
+	void	(*green_led_blink)	(struct slot *slot);
+	void	(*release_ctlr)		(struct controller *ctrl);
+	int (*check_lnk_status)		(struct controller *ctrl);
+};
+
+#endif				/* _PCIEHP_H */
diff -puN /dev/null drivers/pci/hotplug/pciehp_hpc.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehp_hpc.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,1436 @@
+/*
+ * PCI Express PCI Hot Plug Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;,&lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/vmalloc.h&gt;
+#include &lt;linux/interrupt.h&gt;
+#include &lt;linux/spinlock.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;asm/system.h&gt;
+#include "pciehp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
+#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
+#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
+#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
+#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL            DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... )              \
+	do {                                             \
+	  if ( DEBUG_LEVEL &amp; ( dbg_flags ) )             \
+	  {                                              \
+	    int len;                                     \
+	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+		  __FILE__, __LINE__, __FUNCTION__ );    \
+	    sprintf( __dbg_str_buf + len, args );        \
+	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+	  }                                              \
+	} while (0)
+
+#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif				/* DEBUG */
+
+struct ctrl_reg {
+	u8 cap_id;
+	u8 nxt_ptr;
+	u16 cap_reg;
+	u32 dev_cap;
+	u16 dev_ctrl;
+	u16 dev_status;
+	u32 lnk_cap;
+	u16 lnk_ctrl;
+	u16 lnk_status;
+	u32 slot_cap;
+	u16 slot_ctrl;
+	u16 slot_status;
+	u16 root_ctrl;
+	u16 rsvp;
+	u32 root_status;
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	PCIECAPID	=	offsetof(struct ctrl_reg, cap_id),
+	NXTCAPPTR	=	offsetof(struct ctrl_reg, nxt_ptr),
+	CAPREG		=	offsetof(struct ctrl_reg, cap_reg),
+	DEVCAP		=	offsetof(struct ctrl_reg, dev_cap),
+	DEVCTRL		=	offsetof(struct ctrl_reg, dev_ctrl),
+	DEVSTATUS	=	offsetof(struct ctrl_reg, dev_status),
+	LNKCAP		=	offsetof(struct ctrl_reg, lnk_cap),
+	LNKCTRL		=	offsetof(struct ctrl_reg, lnk_ctrl),
+	LNKSTATUS	=	offsetof(struct ctrl_reg, lnk_status),
+	SLOTCAP		=	offsetof(struct ctrl_reg, slot_cap),
+	SLOTCTRL	=	offsetof(struct ctrl_reg, slot_ctrl),
+	SLOTSTATUS	=	offsetof(struct ctrl_reg, slot_status),
+	ROOTCTRL	=	offsetof(struct ctrl_reg, root_ctrl),
+	ROOTSTATUS	=	offsetof(struct ctrl_reg, root_status),
+};
+static int pcie_cap_base = 0;		/* Base of the PCI Express capability item structure */ 
+
+#define PCIE_CAP_ID	( pcie_cap_base + PCIECAPID )
+#define NXT_CAP_PTR	( pcie_cap_base + NXTCAPPTR )
+#define CAP_REG		( pcie_cap_base + CAPREG )
+#define DEV_CAP		( pcie_cap_base + DEVCAP )
+#define DEV_CTRL	( pcie_cap_base + DEVCTRL )
+#define DEV_STATUS	( pcie_cap_base + DEVSTATUS )
+#define LNK_CAP		( pcie_cap_base + LNKCAP )
+#define LNK_CTRL	( pcie_cap_base + LNKCTRL )
+#define LNK_STATUS	( pcie_cap_base + LNKSTATUS )
+#define SLOT_CAP	( pcie_cap_base + SLOTCAP )
+#define SLOT_CTRL	( pcie_cap_base + SLOTCTRL )
+#define SLOT_STATUS	( pcie_cap_base + SLOTSTATUS )
+#define ROOT_CTRL	( pcie_cap_base + ROOTCTRL )
+#define ROOT_STATUS	( pcie_cap_base + ROOTSTATUS )
+
+#define hp_register_read_word(pdev, reg , value)		\
+	pci_read_config_word(pdev, reg, &amp;value)
+
+#define hp_register_read_dword(pdev, reg , value)		\
+	pci_read_config_dword(pdev, reg, &amp;value)
+ 
+#define hp_register_write_word(pdev, reg , value)		\
+	pci_write_config_word(pdev, reg, value)
+
+#define hp_register_dwrite_word(pdev, reg , value)		\
+	pci_write_config_dword(pdev, reg, value)
+
+/* Field definitions in PCI Express Capabilities Register */
+#define CAP_VER			0x000F
+#define DEV_PORT_TYPE		0x00F0
+#define SLOT_IMPL		0x0100
+#define MSG_NUM			0x3E00
+
+/* Device or Port Type */
+#define NAT_ENDPT		0x00
+#define LEG_ENDPT		0x01
+#define ROOT_PORT		0x04
+#define UP_STREAM		0x05
+#define	DN_STREAM		0x06
+#define PCIE_PCI_BRDG		0x07
+#define PCI_PCIE_BRDG		0x10
+
+/* Field definitions in Device Capabilities Register */
+#define DATTN_BUTTN_PRSN	0x1000
+#define DATTN_LED_PRSN		0x2000
+#define DPWR_LED_PRSN		0x4000
+
+/* Field definitions in Link Capabilities Register */
+#define MAX_LNK_SPEED		0x000F
+#define MAX_LNK_WIDTH		0x03F0
+
+/* Link Width Encoding */
+#define LNK_X1		0x01
+#define LNK_X2		0x02
+#define LNK_X4		0x04	
+#define LNK_X8		0x08
+#define LNK_X12		0x0C
+#define LNK_X16		0x10	
+#define LNK_X32		0x20
+
+/*Field definitions of Link Status Register */
+#define LNK_SPEED	0x000F
+#define NEG_LINK_WD	0x03F0
+#define LNK_TRN_ERR	0x0400
+#define	LNK_TRN		0x0800
+#define SLOT_CLK_CONF	0x1000
+
+/* Field definitions in Slot Capabilities Register */
+#define ATTN_BUTTN_PRSN	0x00000001
+#define	PWR_CTRL_PRSN	0x00000002
+#define MRL_SENS_PRSN	0x00000004
+#define ATTN_LED_PRSN	0x00000008
+#define PWR_LED_PRSN	0x00000010
+#define HP_SUPR_RM	0x00000020
+#define HP_CAP		0x00000040
+#define SLOT_PWR_VALUE	0x000003F8
+#define SLOT_PWR_LIMIT	0x00000C00
+#define PSN		0xFFF80000	/* PSN: Physical Slot Number */
+
+/* Field definitions in Slot Control Register */
+#define ATTN_BUTTN_ENABLE		0x0001
+#define PWR_FAULT_DETECT_ENABLE		0x0002
+#define MRL_DETECT_ENABLE		0x0004
+#define PRSN_DETECT_ENABLE		0x0008
+#define CMD_CMPL_INTR_ENABLE		0x0010
+#define HP_INTR_ENABLE			0x0020
+#define ATTN_LED_CTRL			0x00C0
+#define PWR_LED_CTRL			0x0300
+#define PWR_CTRL			0x0400
+
+/* Attention indicator and Power indicator states */
+#define LED_ON		0x01
+#define LED_BLINK	0x10
+#define LED_OFF		0x11
+
+/* Power Control Command */
+#define POWER_ON	0
+#define POWER_OFF	0x0400
+
+/* Field definitions in Slot Status Register */
+#define ATTN_BUTTN_PRESSED	0x0001
+#define PWR_FAULT_DETECTED	0x0002
+#define MRL_SENS_CHANGED	0x0004
+#define PRSN_DETECT_CHANGED	0x0008
+#define CMD_COMPLETED		0x0010
+#define MRL_STATE		0x0020
+#define PRSN_STATE		0x0040
+
+struct php_ctlr_state_s {
+	struct php_ctlr_state_s *pnext;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+	unsigned long flags;				/* spinlock's */
+	u32 slot_device_offset;
+	u32 num_slots;
+    	struct timer_list	int_poll_timer;		/* Added for poll event */
+	php_intr_callback_t 	attention_button_callback;
+	php_intr_callback_t 	switch_change_callback;
+	php_intr_callback_t 	presence_change_callback;
+	php_intr_callback_t 	power_fault_callback;
+	void 			*callback_instance_id;
+	struct ctrl_reg 	*creg;				/* Ptr to controller register space */
+};
+
+
+static spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head = 0;	/* HPC state linked list */
+static int ctlr_seq_num = 0;	/* Controller sequence # */
+static spinlock_t list_lock;
+
+static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+/* This is the interrupt polling timeout function. */
+static void int_poll_timeout(unsigned long lphp_ctlr)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+
+	DBG_ENTER_ROUTINE
+
+	if ( !php_ctlr ) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+	/* Poll for interrupt events.  regs == NULL =&gt; polling */
+	pcie_isr( 0, (void *)php_ctlr, NULL );
+
+	init_timer(&amp;php_ctlr-&gt;int_poll_timer);
+
+	if (!pciehp_poll_time)
+		pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+
+	start_int_poll_timer(php_ctlr, pciehp_poll_time);  
+	
+	return;
+}
+
+/* This function starts the interrupt polling timer. */
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+{
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+	if ( ( seconds &lt;= 0 ) || ( seconds &gt; 60 ) )
+        	seconds = 2;            /* Clamp to sane value */
+
+	php_ctlr-&gt;int_poll_timer.function = &amp;int_poll_timeout;
+	php_ctlr-&gt;int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
+	php_ctlr-&gt;int_poll_timer.expires = jiffies + seconds * HZ;
+	add_timer(&amp;php_ctlr-&gt;int_poll_timer);
+
+	return;
+}
+
+static int pcie_write_cmd(struct slot *slot, u16 cmd)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	int retval = 0;
+	u16 slot_status;
+
+	DBG_ENTER_ROUTINE 
+	
+	dbg("%s : Enter\n", __FUNCTION__);
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+	if (retval) {
+			err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+			return retval;
+		}
+	dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status);
+	
+	if ((slot_status &amp; CMD_COMPLETED) == CMD_COMPLETED ) { 
+		/* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
+		   the next command according to spec.  Just print out the error message */
+		dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+	}
+
+	retval = hp_register_write_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, cmd);
+	if (retval) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd);
+	dbg("%s : Exit\n", __FUNCTION__);
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_check_lnk_status(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl-&gt;hpc_ctlr_handle;
+	u16 lnk_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	if ( (lnk_status &amp; (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) {
+		err("%s : Link Training Error occurs \n", __FUNCTION__);
+		retval = -1;
+		return retval;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_ctrl;
+	u8 atten_led_state;
+	int retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl);
+
+	atten_led_state = (slot_ctrl &amp; ATTN_LED_CTRL) &gt;&gt; 6;
+
+	switch (atten_led_state) {
+	case 0:
+		*status = 0xFF;	/* Reserved */
+		break;
+	case 1:
+		*status = 1;	/* On */
+		break;
+	case 2:
+		*status = 2;	/* Blink */
+		break;
+	case 3:
+		*status = 0;	/* Off */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_ctrl;
+	u8 pwr_state;
+	int	retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+
+	pwr_state = (slot_ctrl &amp; PWR_CTRL) &gt;&gt; 10;
+
+	switch (pwr_state) {
+	case 0:
+		*status = 1;
+		break;
+	case 1:
+		*status = 0;	
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	*status = (((slot_status &amp; MRL_STATE) &gt;&gt; 5) == 0) ? 0 : 1;  
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_status;
+	u8 card_state;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	card_state = (u8)((slot_status &amp; PRSN_STATE) &gt;&gt; 6);
+	*status = (card_state == 1) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_status;
+	u8 pwr_fault;
+	int retval = 0;
+	u8 status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	pwr_fault = (u8)((slot_status &amp; PWR_FAULT_DETECTED) &gt;&gt; 1);
+	status = (pwr_fault != 1) ? 1 : 0;
+	
+	DBG_LEAVE_ROUTINE
+	/* Note: Logic 0 =&gt; fault */
+	return status;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_cmd = 0;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	dbg("%s: \n", __FUNCTION__);
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return rc;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	switch (value) {
+		case 0 :	/* turn off */
+			slot_cmd = (slot_ctrl &amp; ~ATTN_LED_CTRL) | 0x00C0;
+			break;
+		case 1:		/* turn on */
+			slot_cmd = (slot_ctrl &amp; ~ATTN_LED_CTRL) | 0x0040;
+			break;
+		case 2:		/* turn blink */
+			slot_cmd = (slot_ctrl &amp; ~ATTN_LED_CTRL) | 0x0080;
+			break;
+		default:
+			return -1;
+	}
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	pcie_write_cmd(slot, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd);
+	
+	return rc;
+}
+
+
+static void hpc_set_green_led_on(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0;
+       	
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+	slot_cmd = (slot_ctrl &amp; ~PWR_LED_CTRL) | 0x0100;
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+static void hpc_set_green_led_off(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0;
+
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	slot_cmd = (slot_ctrl &amp; ~PWR_LED_CTRL) | 0x0300;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	pcie_write_cmd(slot, slot_cmd);
+	dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_blink(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+	int rc = 0; 
+	
+	dbg("%s: \n", __FUNCTION__);	
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return;
+	}
+	dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
+
+	slot_cmd = (slot_ctrl &amp; ~PWR_LED_CTRL) | 0x0200;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+	pcie_write_cmd(slot, slot_cmd);
+
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+	return;
+}
+
+int pcie_get_ctlr_slot_config(struct controller *ctrl,
+	int *num_ctlr_slots,	/* number of slots in this HPC; only 1 in PCIE  */	
+	int *first_device_num,	/* PCI dev num of the first slot in this PCIE	*/
+	int *physical_slot_num,	/* phy slot num of the first slot in this PCIE	*/
+	int *updown,		/* physical_slot_num increament: 1 or -1	*/
+	int *flags)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_cap;
+	int rc = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*first_device_num = 0;
+	*num_ctlr_slots = 1; 
+
+	rc = hp_register_read_dword(php_ctlr-&gt;pci_dev, SLOT_CAP, slot_cap);
+
+	if (rc) {
+		err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
+		return -1;
+	}
+	
+	*physical_slot_num = slot_cap &gt;&gt; 19;
+
+	*updown = -1;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl-&gt;hpc_ctlr_handle;
+	struct php_ctlr_state_s *p, *p_prev;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (pciehp_poll_mode) {
+	    del_timer(&amp;php_ctlr-&gt;int_poll_timer);
+	} else {	
+		if (php_ctlr-&gt;irq) {
+			free_irq(php_ctlr-&gt;irq, ctrl);
+			php_ctlr-&gt;irq = 0;
+		}
+	}
+	if (php_ctlr-&gt;pci_dev) 
+		php_ctlr-&gt;pci_dev = 0;
+
+	spin_lock(&amp;list_lock);
+	p = php_ctlr_list_head;
+	p_prev = NULL;
+	while (p) {
+		if (p == php_ctlr) {
+			if (p_prev)
+				p_prev-&gt;pnext = p-&gt;pnext;
+			else
+				php_ctlr_list_head = p-&gt;pnext;
+			break;
+		} else {
+			p_prev = p;
+			p = p-&gt;pnext;
+		}
+	}
+	spin_unlock(&amp;list_lock);
+
+	kfree(php_ctlr);
+
+	DBG_LEAVE_ROUTINE
+			  
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	dbg("%s: \n", __FUNCTION__);	
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	dbg("%s: slot-&gt;hp_slot %x\n", __FUNCTION__, slot-&gt;hp_slot);
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL, 
+		slot_ctrl);
+
+	slot_cmd = (slot_ctrl &amp; ~PWR_CTRL) | POWER_ON;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	retval = pcie_write_cmd(slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
+		return -1;
+	}
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_power_off_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 slot_cmd;
+	u16 slot_ctrl;
+
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	dbg("%s: \n", __FUNCTION__);	
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	dbg("%s: slot-&gt;hp_slot %x\n", __FUNCTION__, slot-&gt;hp_slot);
+	slot-&gt;hp_slot = 0;
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+
+	if (retval) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		return retval;
+	}
+	dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL, 
+		slot_ctrl);
+
+	slot_cmd = (slot_ctrl &amp; ~PWR_CTRL) | POWER_OFF;
+
+	if (!pciehp_poll_mode)
+		slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+
+	retval = pcie_write_cmd(slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+	dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+	struct controller *ctrl = NULL;
+	struct php_ctlr_state_s *php_ctlr;
+	u8 schedule_flag = 0;
+	u16 slot_status, intr_detect, intr_loc;
+	u16 temp_word;
+	int hp_slot = 0;	/* only 1 slot per PCI Express port */
+	int rc = 0;
+
+	if (!dev_id)
+		return IRQ_NONE;
+
+	if (!pciehp_poll_mode) { 
+		ctrl = (struct controller *)dev_id;
+		php_ctlr = ctrl-&gt;hpc_ctlr_handle;
+	} else {
+		php_ctlr = (struct php_ctlr_state_s *) dev_id;
+		ctrl = (struct controller *)php_ctlr-&gt;callback_instance_id;
+	}
+
+	if (!ctrl) {
+		dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
+		return IRQ_NONE;
+	}
+	
+	if (!php_ctlr) {
+		dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
+		return IRQ_NONE;
+	}
+
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		return IRQ_NONE;
+	}
+
+	intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
+					PRSN_DETECT_CHANGED | CMD_COMPLETED );
+
+	intr_loc = slot_status &amp; intr_detect;
+
+	/* Check to see if it was our interrupt */
+	if ( !intr_loc )
+		return IRQ_NONE;
+
+	dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
+	/* Mask Hot-plug Interrupt Enable */
+	if (!pciehp_poll_mode) {
+		rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;;
+		}
+
+		temp_word = (temp_word &amp; ~HP_INTR_ENABLE) | 0x00;
+
+		rc = hp_register_write_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;;
+		}
+	}
+	
+	if (intr_loc &amp; CMD_COMPLETED) {
+		/* 
+		 * Command Complete Interrupt Pending 
+		 */
+		dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__);
+		wake_up_interruptible(&amp;ctrl-&gt;queue);
+	}
+
+	if ((php_ctlr-&gt;switch_change_callback) &amp;&amp; (intr_loc &amp; MRL_SENS_CHANGED))
+		schedule_flag += php_ctlr-&gt;switch_change_callback(
+			hp_slot, php_ctlr-&gt;callback_instance_id);
+	if ((php_ctlr-&gt;attention_button_callback) &amp;&amp; (intr_loc &amp; ATTN_BUTTN_PRESSED))
+		schedule_flag += php_ctlr-&gt;attention_button_callback(
+			hp_slot, php_ctlr-&gt;callback_instance_id);
+	if ((php_ctlr-&gt;presence_change_callback) &amp;&amp; (intr_loc &amp; PRSN_DETECT_CHANGED))
+		schedule_flag += php_ctlr-&gt;presence_change_callback(
+			hp_slot , php_ctlr-&gt;callback_instance_id);
+	if ((php_ctlr-&gt;power_fault_callback) &amp;&amp; (intr_loc &amp; PWR_FAULT_DETECTED))
+		schedule_flag += php_ctlr-&gt;power_fault_callback(
+			hp_slot, php_ctlr-&gt;callback_instance_id);
+
+	/* Clear all events after serving them */
+	temp_word = slot_status | 0xff;
+	rc = hp_register_write_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		return IRQ_NONE;
+	}
+	/* Unmask Hot-plug Interrupt Enable */
+	if (!pciehp_poll_mode) {
+		rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+
+		temp_word = (temp_word &amp; ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+
+		rc = hp_register_write_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, temp_word);
+		if (rc) {
+			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+			return IRQ_NONE;
+		}
+	}
+	
+	return IRQ_HANDLED;
+}
+
+static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	enum pcie_link_speed lnk_speed;
+	u32	lnk_cap;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_dword(php_ctlr-&gt;pci_dev, LNK_CAP, lnk_cap);
+
+	if (retval) {
+		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch (lnk_cap &amp; 0x000F) {
+	case 1:
+		lnk_speed = PCIE_2PT5GB;
+		break;
+	default:
+		lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_speed;
+	dbg("Max link speed = %d\n", lnk_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	enum pcie_link_width lnk_wdth;
+	u32	lnk_cap;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_dword(php_ctlr-&gt;pci_dev, LNK_CAP, lnk_cap);
+
+	if (retval) {
+		err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch ((lnk_cap &amp; 0x03F0) &gt;&gt; 4){
+	case 0:
+		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
+		break;
+	case 1:
+		lnk_wdth = PCIE_LNK_X1;
+		break;
+	case 2:
+		lnk_wdth = PCIE_LNK_X2;
+		break;
+	case 4:
+		lnk_wdth = PCIE_LNK_X4;
+		break;
+	case 8:
+		lnk_wdth = PCIE_LNK_X8;
+		break;
+	case 12:
+		lnk_wdth = PCIE_LNK_X12;
+		break;
+	case 16:
+		lnk_wdth = PCIE_LNK_X16;
+		break;
+	case 32:
+		lnk_wdth = PCIE_LNK_X32;
+		break;
+	default:
+		lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_wdth;
+	dbg("Max link width = %d\n", lnk_wdth);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
+	int retval = 0;
+	u16 lnk_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+
+	switch (lnk_status &amp; 0x0F) {
+	case 1:
+		lnk_speed = PCIE_2PT5GB;
+		break;
+	default:
+		lnk_speed = PCIE_LNK_SPEED_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_speed;
+	dbg("Current link speed = %d\n", lnk_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+	int retval = 0;
+	u16 lnk_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = hp_register_read_word(php_ctlr-&gt;pci_dev, LNK_STATUS, lnk_status);
+
+	if (retval) {
+		err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+		return retval;
+	}
+	
+	switch ((lnk_status &amp; 0x03F0) &gt;&gt; 4){
+	case 0:
+		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
+		break;
+	case 1:
+		lnk_wdth = PCIE_LNK_X1;
+		break;
+	case 2:
+		lnk_wdth = PCIE_LNK_X2;
+		break;
+	case 4:
+		lnk_wdth = PCIE_LNK_X4;
+		break;
+	case 8:
+		lnk_wdth = PCIE_LNK_X8;
+		break;
+	case 12:
+		lnk_wdth = PCIE_LNK_X12;
+		break;
+	case 16:
+		lnk_wdth = PCIE_LNK_X16;
+		break;
+	case 32:
+		lnk_wdth = PCIE_LNK_X32;
+		break;
+	default:
+		lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	*value = lnk_wdth;
+	dbg("Current link width = %d\n", lnk_wdth);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static struct hpc_ops pciehp_hpc_ops = {
+	.power_on_slot			= hpc_power_on_slot,
+	.power_off_slot			= hpc_power_off_slot,
+	.set_attention_status		= hpc_set_attention_status,
+	.get_power_status		= hpc_get_power_status,
+	.get_attention_status		= hpc_get_attention_status,
+	.get_latch_status		= hpc_get_latch_status,
+	.get_adapter_status		= hpc_get_adapter_status,
+
+	.get_max_bus_speed		= hpc_get_max_lnk_speed,
+	.get_cur_bus_speed		= hpc_get_cur_lnk_speed,
+	.get_max_lnk_width		= hpc_get_max_lnk_width,
+	.get_cur_lnk_width		= hpc_get_cur_lnk_width,
+	
+	.query_power_fault		= hpc_query_power_fault,
+	.green_led_on			= hpc_set_green_led_on,
+	.green_led_off			= hpc_set_green_led_off,
+	.green_led_blink		= hpc_set_green_led_blink,
+	
+	.release_ctlr			= hpc_release_ctlr,
+	.check_lnk_status		= hpc_check_lnk_status,
+};
+
+int pcie_init(struct controller * ctrl,
+	struct pci_dev * pdev,
+	php_intr_callback_t attention_button_callback,
+	php_intr_callback_t switch_change_callback,
+	php_intr_callback_t presence_change_callback,
+	php_intr_callback_t power_fault_callback)
+{
+	struct php_ctlr_state_s *php_ctlr, *p;
+	void *instance_id = ctrl;
+	int rc;
+	static int first = 1;
+	u16 temp_word;
+	u16 cap_reg;
+	u16 intr_enable;
+	u32 slot_cap;
+	int cap_base, saved_cap_base;
+	u16 slot_status, slot_ctrl;
+
+	DBG_ENTER_ROUTINE
+	
+	spin_lock_init(&amp;list_lock);	
+	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+	if (!php_ctlr) {	/* allocate controller state data */
+		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+		goto abort;
+	}
+
+	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+
+	php_ctlr-&gt;pci_dev = pdev;	/* save pci_dev in context */
+
+	dbg("%s: pdev-&gt;vendor %x pdev-&gt;device %x\n", __FUNCTION__,
+		pdev-&gt;vendor, pdev-&gt;device);
+
+	saved_cap_base = pcie_cap_base;
+
+	if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
+		dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	pcie_cap_base = cap_base;
+
+	dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+
+	rc = hp_register_read_word(pdev, CAP_REG, cap_reg);
+	if (rc) {
+		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg);
+
+	if (((cap_reg &amp; SLOT_IMPL) == 0) || ((cap_reg &amp; DEV_PORT_TYPE) != 0x0040)){
+		dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	rc = hp_register_read_dword(php_ctlr-&gt;pci_dev, SLOT_CAP, slot_cap);
+	if (rc) {
+		err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap);
+
+	if (!(slot_cap &amp; HP_CAP)) {
+		dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	/* For debugging purpose */
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_CTRL, slot_ctrl);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+
+	if (first) {
+		spin_lock_init(&amp;hpc_event_lock);
+		first = 0;
+	}
+
+	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev-&gt;bus-&gt;number, 
+		PCI_SLOT(pdev-&gt;devfn), PCI_FUNC(pdev-&gt;devfn), pdev-&gt;irq);
+	for ( rc = 0; rc &lt; DEVICE_COUNT_RESOURCE; rc++)
+		if (pci_resource_len(pdev, rc) &gt; 0)
+			dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
+				pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev-&gt;vendor, pdev-&gt;device, 
+		pdev-&gt;subsystem_vendor, pdev-&gt;subsystem_device);
+
+	init_MUTEX(&amp;ctrl-&gt;crit_sect);
+	/* setup wait queue */
+	init_waitqueue_head(&amp;ctrl-&gt;queue);
+
+	/* find the IRQ */
+	php_ctlr-&gt;irq = pdev-&gt;irq;
+	dbg("HPC interrupt = %d\n", php_ctlr-&gt;irq);
+
+	/* Save interrupt callback info */
+	php_ctlr-&gt;attention_button_callback = attention_button_callback;
+	php_ctlr-&gt;switch_change_callback = switch_change_callback;
+	php_ctlr-&gt;presence_change_callback = presence_change_callback;
+	php_ctlr-&gt;power_fault_callback = power_fault_callback;
+	php_ctlr-&gt;callback_instance_id = instance_id;
+
+	/* return PCI Controller Info */
+	php_ctlr-&gt;slot_device_offset = 0;
+	php_ctlr-&gt;num_slots = 1;
+
+	/* Mask Hot-plug Interrupt Enable */
+	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+	temp_word = (temp_word &amp; ~HP_INTR_ENABLE) | 0x00;
+
+	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word);
+
+	rc = hp_register_read_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+
+	rc = hp_register_write_word(php_ctlr-&gt;pci_dev, SLOT_STATUS, slot_status);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+
+	if (pciehp_poll_mode)  {/* Install interrupt polling code */
+		/* Install and start the interrupt polling timer */
+		init_timer(&amp;php_ctlr-&gt;int_poll_timer);
+		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	} else {
+		/* Installs the interrupt handler */
+#ifdef CONFIG_PCI_USE_VECTOR 
+		rc = pci_enable_msi(pdev);
+		if (rc) {
+			err("Can't get msi for the hotplug controller\n");
+			dbg("%s: rc = %x\n", __FUNCTION__, rc);
+			goto abort_free_ctlr;
+		}
+		php_ctlr-&gt;irq = pdev-&gt;irq;
+#endif		
+		rc = request_irq(php_ctlr-&gt;irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr-&gt;irq, ctlr_seq_num, rc);
+		if (rc) {
+			err("Can't get irq %d for the hotplug controller\n", php_ctlr-&gt;irq);
+			goto abort_free_ctlr;
+		}
+	}
+
+	rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+
+	intr_enable = ATTN_BUTTN_ENABLE | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+					PRSN_DETECT_ENABLE | CMD_CMPL_INTR_ENABLE;
+
+	temp_word = (temp_word &amp; ~intr_enable) | intr_enable; 
+
+	if (pciehp_poll_mode) {
+		temp_word = (temp_word &amp; ~HP_INTR_ENABLE) | 0x0;
+	} else {
+		temp_word = (temp_word &amp; ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
+	}
+	dbg("%s: temp_word %x\n", __FUNCTION__, temp_word);
+
+	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+	rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+	if (rc) {
+		err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+	dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word);
+	
+	/*  Add this HPC instance into the HPC list */
+	spin_lock(&amp;list_lock);
+	if (php_ctlr_list_head == 0) {
+		php_ctlr_list_head = php_ctlr;
+		p = php_ctlr_list_head;
+		p-&gt;pnext = 0;
+	} else {
+		p = php_ctlr_list_head;
+
+		while (p-&gt;pnext)
+			p = p-&gt;pnext;
+
+		p-&gt;pnext = php_ctlr;
+	}
+	spin_unlock(&amp;list_lock);
+
+	ctlr_seq_num++;
+	ctrl-&gt;hpc_ctlr_handle = php_ctlr;
+	ctrl-&gt;hpc_ops = &amp;pciehp_hpc_ops;
+
+	DBG_LEAVE_ROUTINE
+	return 0;
+
+	/* We end up here for the many possible ways to fail this API.  */
+abort_free_ctlr:
+	pcie_cap_base = saved_cap_base;
+	kfree(php_ctlr);
+abort:
+	DBG_LEAVE_ROUTINE
+	return -1;
+}
diff -puN /dev/null drivers/pci/hotplug/pciehp_pci.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehp_pci.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,834 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/pci.h&gt;
+#include "../pci.h"
+#include "pciehp.h"
+#ifndef CONFIG_IA64
+#include "../../../arch/i386/pci/pci.h"    /* horrible hack showing how processor dependant we are... */
+#endif
+
+
+int pciehp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_bus *child;
+	int num;
+
+	if (func-&gt;pci_dev == NULL)
+		func-&gt;pci_dev = pci_find_slot(func-&gt;bus, PCI_DEVFN(func-&gt;device, func-&gt;function));
+
+	/* Still NULL ? Well then scan for it ! */
+	if (func-&gt;pci_dev == NULL) {
+		dbg("%s: pci_dev still null. do pci_scan_slot\n", __FUNCTION__);
+
+		num = pci_scan_slot(ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(func-&gt;device, func-&gt;function));
+
+		if (num)
+			pci_bus_add_devices(ctrl-&gt;pci_dev-&gt;subordinate);
+		
+		func-&gt;pci_dev = pci_find_slot(func-&gt;bus, PCI_DEVFN(func-&gt;device, func-&gt;function));
+		if (func-&gt;pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func-&gt;pci_dev-&gt;hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func-&gt;pci_dev, PCI_SECONDARY_BUS, &amp;bus);
+		child = (struct pci_bus*) pci_add_new_bus(func-&gt;pci_dev-&gt;bus, (func-&gt;pci_dev), bus);
+		pci_do_scan_bus(child);
+
+	}
+
+	return 0;
+}
+
+
+int pciehp_unconfigure_device(struct pci_func* func) 
+{
+	int rc = 0;
+	int j;
+
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+
+	for (j=0; j&lt;8 ; j++) {
+		struct pci_dev* temp = pci_find_slot(func-&gt;bus, (func-&gt;device &lt;&lt; 3) | j);
+		if (temp) {
+			pci_remove_bus_device(temp);
+		}
+	}
+	return rc;
+}
+
+/*
+ * pciehp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int pciehp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+#if !defined(CONFIG_X86_IO_APIC) &amp;&amp; !defined(CONFIG_X86_64)
+	int rc;
+	u16 temp_word;
+	struct pci_dev fakedev;
+	struct pci_bus fakebus;
+
+	fakedev.devfn = dev_num &lt;&lt; 3;
+	fakedev.bus = &amp;fakebus;
+	fakebus.number = bus_num;
+	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
+	rc = pcibios_set_irq_routing(&amp;fakedev, int_pin - 0x0a, irq_num);
+	dbg("%s: rc %d\n", __FUNCTION__, rc);
+	if (!rc)
+		return !rc;
+
+	/* set the Edge Level Control Register (ELCR) */
+	temp_word = inb(0x4d0);
+	temp_word |= inb(0x4d1) &lt;&lt; 8;
+
+	temp_word |= 0x01 &lt;&lt; irq_num;
+
+	/* This should only be for x86 as it sets the Edge Level Control Register */
+	outb((u8) (temp_word &amp; 0xFF), 0x4d0);
+	outb((u8) ((temp_word &amp; 0xFF00) &gt;&gt; 8), 0x4d1);
+#endif
+	return 0;
+}
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * pciehp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int pciehp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+	int is_hot_plug = num_ctlr_slots || first_device_num;
+	struct pci_bus lpci_bus, *pci_bus;
+	int FirstSupported, LastSupported;
+
+	dbg("%s: Enter\n", __FUNCTION__);
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num);
+
+	/*   Decide which slots are supported */
+	if (is_hot_plug) {
+		/*********************************
+		 *  is_hot_plug is the slot mask
+		 *********************************/
+		FirstSupported = first_device_num;
+		LastSupported = FirstSupported + num_ctlr_slots - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported);
+
+	/*   Save PCI configuration space for all devices in supported slots */
+	dbg("%s: pci_bus-&gt;number = %x\n", __FUNCTION__, pci_bus-&gt;number);
+	pci_bus-&gt;number = busnumber;
+	dbg("%s: bus = %x, dev = %x\n", __FUNCTION__, busnumber, device);
+	for (device = FirstSupported; device &lt;= LastSupported; device++) {
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &amp;ID);
+		dbg("%s: ID = %x\n", __FUNCTION__, ID);
+
+		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+			dbg("%s: ID = %x\n", __FUNCTION__, ID);
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &amp;class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &amp;header_type);
+			if (rc)
+				return rc;
+
+			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+			/* If multi-function device, set max_functions to 8 */
+			if (header_type &amp; 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+				dbg("%s: In do loop\n", __FUNCTION__);
+
+				if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
+					/* Recurse the subordinate bus
+					 * get the subordinate bus number
+					 */
+					rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 
+						PCI_SECONDARY_BUS, &amp;secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						/* Save secondary bus cfg spc with this recursive call. */
+						rc = pciehp_save_config(ctrl, sub_bus, 0, 0);
+						if (rc)
+							return rc;
+					}
+				}
+
+				index = 0;
+				new_slot = pciehp_slot_find(busnumber, device, index++);
+
+				dbg("%s: new_slot = %p bus %x dev %x fun %x\n",
+				__FUNCTION__, new_slot, busnumber, device, index-1);
+
+				while (new_slot &amp;&amp; (new_slot-&gt;function != (u8) function)) {
+					new_slot = pciehp_slot_find(busnumber, device, index++);
+					dbg("%s: while loop, new_slot = %p bus %x dev %x fun %x\n",
+					__FUNCTION__, new_slot, busnumber, device, index-1);
+				}
+				if (!new_slot) {
+					/* Setup slot structure. */
+					new_slot = pciehp_slot_create(busnumber);
+					dbg("%s: if, new_slot = %p bus %x dev %x fun %x\n",
+					__FUNCTION__, new_slot, busnumber, device, function);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot-&gt;bus = (u8) busnumber;
+				new_slot-&gt;device = (u8) device;
+				new_slot-&gt;function = (u8) function;
+				new_slot-&gt;is_a_board = 1;
+				new_slot-&gt;switch_save = 0x10;
+				/* In case of unsupported board */
+				new_slot-&gt;status = DevError;
+				new_slot-&gt;pci_dev = pci_find_slot(new_slot-&gt;bus, (new_slot-&gt;device &lt;&lt; 3) | new_slot-&gt;function);
+				dbg("new_slot-&gt;pci_dev = %p\n", new_slot-&gt;pci_dev);
+
+				for (cloop = 0; cloop &lt; 0x20; cloop++) {
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), cloop &lt;&lt; 2, 
+						(u32 *) &amp; (new_slot-&gt;config_space [cloop]));
+					/* dbg("new_slot-&gt;config_space[%x] = %x\n", cloop, new_slot-&gt;config_space[cloop]); */
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				/*  this loop skips to the next present function
+				 *  reading in Class Code and Header type.
+				 */
+
+				while ((function &lt; max_functions)&amp;&amp;(!stop_it)) {
+					dbg("%s: In while loop \n", __FUNCTION__);
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &amp;ID);
+
+					if (ID == 0xFFFFFFFF) {  /* nothing there. */
+						function++;
+						dbg("Nothing there\n");
+					} else {  /* Something there */
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 0x0B, 
+							&amp;class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, 
+							&amp;header_type);
+						if (rc)
+							return rc;
+
+						dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+						stop_it++;
+					}
+				}
+
+			} while (function &lt; max_functions);
+		}		/* End of IF (device in slot?) */
+		else if (is_hot_plug) {
+			/* Setup slot structure with entry for empty slot */
+			new_slot = pciehp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+			dbg("new_slot = %p, bus = %x, dev = %x, fun = %x\n", new_slot,
+				new_slot-&gt;bus, new_slot-&gt;device, new_slot-&gt;function);
+
+			new_slot-&gt;bus = (u8) busnumber;
+			new_slot-&gt;device = (u8) device;
+			new_slot-&gt;function = 0;
+			new_slot-&gt;is_a_board = 0;
+			new_slot-&gt;presence_save = 0;
+			new_slot-&gt;switch_save = 0;
+		}
+		dbg("%s: End of For loop\n", __FUNCTION__);
+	} 			/* End of FOR loop */
+
+	dbg("%s: Exit\n", __FUNCTION__);
+	return(0);
+}
+
+
+/*
+ * pciehp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int pciehp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = new_slot-&gt;bus;
+
+	ID = 0xFFFFFFFF;
+
+	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot-&gt;device, 0), PCI_VENDOR_ID, &amp;ID);
+
+	if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, 0), 0x0B, &amp;class_code);
+
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, 0), PCI_HEADER_TYPE, &amp;header_type);
+
+		if (header_type &amp; 0x80)	/* Multi-function device */
+			max_functions = 8;
+		else
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
+				/*  Recurse the subordinate bus */
+				pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), 
+					PCI_SECONDARY_BUS, &amp;secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				/* Save the config headers for the secondary bus. */
+				rc = pciehp_save_config(ctrl, sub_bus, 0, 0);
+
+				if (rc)
+					return(rc);
+
+			}	/* End of IF */
+
+			new_slot-&gt;status = 0;
+
+			for (cloop = 0; cloop &lt; 0x20; cloop++) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), 
+					cloop &lt;&lt; 2, (u32 *) &amp; (new_slot-&gt;config_space [cloop]));
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			/*  this loop skips to the next present function
+			 *  reading in the Class Code and the Header type.
+			 */
+
+			while ((function &lt; max_functions) &amp;&amp; (!stop_it)) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), PCI_VENDOR_ID, &amp;ID);
+
+				if (ID == 0xFFFFFFFF) {	 /* nothing there. */
+					function++;
+				} else {  /* Something there */
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), 0x0B, &amp;class_code);
+
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), PCI_HEADER_TYPE, 
+						&amp;header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function &lt; max_functions);
+	}			/* End of IF (device in slot?) */
+	else {
+		return(2);
+	}
+
+	return(0);
+}
+
+
+/*
+ * pciehp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ * if disable  == 1(DISABLE_CARD),
+ *  it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
+ */
+int pciehp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u16 command;
+	u16 save_command;
+	u16 w_base, w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base, length;
+	u64 base64 = 0;
+	int index = 0;
+	unsigned int devfn;
+	struct pci_resource *mem_node = NULL;
+	struct pci_resource *p_mem_node = NULL;
+	struct pci_resource *t_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+
+	if (disable)
+		func = pciehp_slot_find(func-&gt;bus, func-&gt;device, index++);
+
+	while ((func != NULL) &amp;&amp; func-&gt;is_a_board) {
+		pci_bus-&gt;number = func-&gt;bus;
+		devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+		/* Save the command register */
+		pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &amp;save_command);
+
+		if (disable) {
+			/* disable card */
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+		}
+
+		/* Check for Bridge */
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &amp;header_type);
+
+		if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
+			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func-&gt;bus, func-&gt;device, save_command);
+			if (disable) {
+				/* Clear Bridge Control Register */
+				command = 0x00;
+				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			}
+
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &amp;secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &amp;temp_byte);
+
+			bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node-&gt;base = (ulong)secondary_bus;
+			bus_node-&gt;length = (ulong)(temp_byte - secondary_bus + 1);
+
+			bus_node-&gt;next = func-&gt;bus_head;
+			func-&gt;bus_head = bus_node;
+
+			/* Save IO base and Limit registers */
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &amp;temp_byte);
+			base = temp_byte;
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &amp;temp_byte);
+			length = temp_byte;
+
+			if ((base &lt;= length) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_IO))) {
+				io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node-&gt;base = (ulong)(base &amp; PCI_IO_RANGE_MASK) &lt;&lt; 8;
+				io_node-&gt;length = (ulong)(length - base + 0x10) &lt;&lt; 8;
+
+				io_node-&gt;next = func-&gt;io_head;
+				func-&gt;io_head = io_node;
+			}
+
+			/* Save memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &amp;w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &amp;w_length);
+
+			if ((w_base &lt;= w_length) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_MEMORY))) {
+				mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node-&gt;base = (ulong)w_base &lt;&lt; 16;
+				mem_node-&gt;length = (ulong)(w_length - w_base + 0x10) &lt;&lt; 16;
+
+				mem_node-&gt;next = func-&gt;mem_head;
+				func-&gt;mem_head = mem_node;
+			}
+			/* Save prefetchable memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &amp;w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &amp;w_length);
+
+			if ((w_base &lt;= w_length) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_MEMORY))) {
+				p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node-&gt;base = (ulong)w_base &lt;&lt; 16;
+				p_mem_node-&gt;length = (ulong)(w_length - w_base + 0x10) &lt;&lt; 16;
+
+				p_mem_node-&gt;next = func-&gt;p_mem_head;
+				func-&gt;p_mem_head = p_mem_node;
+			}
+		} else if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func-&gt;bus, func-&gt;device, save_command);
+
+			/* Figure out IO and memory base lengths */
+			for (cloop = PCI_BASE_ADDRESS_0; cloop &lt;= PCI_BASE_ADDRESS_5; cloop += 4) {
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &amp;save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &amp;temp_register);
+
+				if (!disable) {
+					pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base);
+				}
+
+				if (!temp_register)
+					continue;
+
+				base = temp_register;
+
+				if ((base &amp; PCI_BASE_ADDRESS_SPACE_IO) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_IO))) {
+					/* IO base */
+					/* set temp_register = amount of IO space requested */
+					base = base &amp; 0xFFFFFFFCL;
+					base = (~base) + 1;
+
+					io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!io_node)
+						return -ENOMEM;
+
+					io_node-&gt;base = (ulong)save_base &amp; PCI_BASE_ADDRESS_IO_MASK;
+					io_node-&gt;length = (ulong)base;
+					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node-&gt;base, io_node-&gt;length);
+
+					io_node-&gt;next = func-&gt;io_head;
+					func-&gt;io_head = io_node;
+				} else {  /* map Memory */
+					int prefetchable = 1;
+					/* struct pci_resources **res_node; */
+					char *res_type_str = "PMEM";
+					u32 temp_register2;
+
+					t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!t_mem_node)
+						return -ENOMEM;
+
+					if (!(base &amp; PCI_BASE_ADDRESS_MEM_PREFETCH) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_MEMORY))) {
+						prefetchable = 0;
+						mem_node = t_mem_node;
+						res_type_str++;
+					} else
+						p_mem_node = t_mem_node;
+
+					base = base &amp; 0xFFFFFFF0L;
+					base = (~base) + 1;
+
+					switch (temp_register &amp; PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+					case PCI_BASE_ADDRESS_MEM_TYPE_32:
+						if (prefetchable) {
+							p_mem_node-&gt;base = (ulong)save_base &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node-&gt;length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, 
+								p_mem_node-&gt;base, p_mem_node-&gt;length);
+
+							p_mem_node-&gt;next = func-&gt;p_mem_head;
+							func-&gt;p_mem_head = p_mem_node;
+						} else {
+							mem_node-&gt;base = (ulong)save_base &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node-&gt;length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, 
+								mem_node-&gt;base, mem_node-&gt;length);
+
+							mem_node-&gt;next = func-&gt;mem_head;
+							func-&gt;mem_head = mem_node;
+						}
+						break;
+					case PCI_BASE_ADDRESS_MEM_TYPE_64:
+						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &amp;temp_register2);
+						base64 = temp_register2;
+						base64 = (base64 &lt;&lt; 32) | save_base;
+
+						if (temp_register2) {
+							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", 
+								res_type_str, temp_register2, (u32)base64);
+							base64 &amp;= 0x00000000FFFFFFFFL;
+						}
+
+						if (prefetchable) {
+							p_mem_node-&gt;base = base64 &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node-&gt;length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, 
+								p_mem_node-&gt;base, p_mem_node-&gt;length);
+
+							p_mem_node-&gt;next = func-&gt;p_mem_head;
+							func-&gt;p_mem_head = p_mem_node;
+						} else {
+							mem_node-&gt;base = base64 &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node-&gt;length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, 
+								mem_node-&gt;base, mem_node-&gt;length);
+
+							mem_node-&gt;next = func-&gt;mem_head;
+							func-&gt;mem_head = mem_node;
+						}
+						cloop += 4;
+						break;
+					default:
+						dbg("asur: reserved BAR type=0x%x\n", temp_register);
+						break;
+					}
+				} 
+			}	/* End of base register loop */
+		} else {	/* Some other unknown header type */
+			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func-&gt;bus, func-&gt;device);
+		}
+
+		/* find the next device in this slot */
+		if (!disable)
+			break;
+		func = pciehp_slot_find(func-&gt;bus, func-&gt;device, index++);
+	}
+
+	return(0);
+}
+
+
+/*
+ * pciehp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int pciehp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
+{
+	int rc = 0;
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return(1);
+
+	node = func-&gt;io_head;
+	func-&gt;io_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;io_head), node);
+		node = t_node;
+	}
+
+	node = func-&gt;mem_head;
+	func-&gt;mem_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;mem_head), node);
+		node = t_node;
+	}
+
+	node = func-&gt;p_mem_head;
+	func-&gt;p_mem_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;p_mem_head), node);
+		node = t_node;
+	}
+
+	node = func-&gt;bus_head;
+	func-&gt;bus_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;bus_head), node);
+		node = t_node;
+	}
+
+	rc |= pciehp_resource_sort_and_combine(&amp;(resources-&gt;mem_head));
+	rc |= pciehp_resource_sort_and_combine(&amp;(resources-&gt;p_mem_head));
+	rc |= pciehp_resource_sort_and_combine(&amp;(resources-&gt;io_head));
+	rc |= pciehp_resource_sort_and_combine(&amp;(resources-&gt;bus_head));
+
+	return(rc);
+}
+
+
+/*
+ * pciehp_destroy_resource_list
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void pciehp_destroy_resource_list (struct resource_lists * resources)
+{
+	struct pci_resource *res, *tres;
+
+	res = resources-&gt;io_head;
+	resources-&gt;io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = resources-&gt;mem_head;
+	resources-&gt;mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = resources-&gt;p_mem_head;
+	resources-&gt;p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = resources-&gt;bus_head;
+	resources-&gt;bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+}
+
+
+/*
+ * pciehp_destroy_board_resources
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void pciehp_destroy_board_resources (struct pci_func * func)
+{
+	struct pci_resource *res, *tres;
+
+	res = func-&gt;io_head;
+	func-&gt;io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = func-&gt;mem_head;
+	func-&gt;mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = func-&gt;p_mem_head;
+	func-&gt;p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = func-&gt;bus_head;
+	func-&gt;bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+}
+
diff -puN /dev/null drivers/pci/hotplug/pciehprm_acpi.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehprm_acpi.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,1689 @@
+/*
+ * PCIEHPRM ACPI: PHP Resource Manager for ACPI platform
+ *
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;linux/acpi.h&gt;
+#include &lt;linux/efi.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include &lt;asm/system.h&gt;
+#ifdef	CONFIG_IA64
+#include &lt;asm/iosapic.h&gt;
+#endif
+#include &lt;acpi/acpi.h&gt;
+#include &lt;acpi/acpi_bus.h&gt;
+#include &lt;acpi/actypes.h&gt;
+#include "pciehp.h"
+#include "pciehprm.h"
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#define	METHOD_NAME__SUN	"_SUN"
+#define	METHOD_NAME__HPP	"_HPP"
+#define	METHOD_NAME_OSHP	"OSHP"
+
+#define	PHP_RES_BUS		0xA0
+#define	PHP_RES_IO		0xA1
+#define	PHP_RES_MEM		0xA2
+#define	PHP_RES_PMEM		0xA3
+
+#define	BRIDGE_TYPE_P2P		0x00
+#define	BRIDGE_TYPE_HOST	0x01
+
+/* this should go to drivers/acpi/include/ */
+struct acpi__hpp {
+	u8	cache_line_size;
+	u8	latency_timer;
+	u8	enable_serr;
+	u8	enable_perr;
+};
+
+struct acpi_php_slot {
+	struct acpi_php_slot	*next;
+	struct acpi_bridge	*bridge;
+	acpi_handle	handle;
+	int	seg;
+	int	bus;
+	int	dev;
+	int	fun;
+	u32	sun;
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	void	*slot_ops;	/* _STA, _EJx, etc */
+	struct slot *slot;
+};		/* per func */
+
+struct acpi_bridge {
+	struct acpi_bridge	*parent;
+	struct acpi_bridge	*next;
+	struct acpi_bridge	*child;
+	acpi_handle	handle;
+	int seg;
+	int pbus;			/* pdev-&gt;bus-&gt;number		*/
+	int pdevice;			/* PCI_SLOT(pdev-&gt;devfn)	*/
+	int pfunction;			/* PCI_DEVFN(pdev-&gt;devfn)	*/
+	int bus;			/* pdev-&gt;subordinate-&gt;number	*/
+	struct acpi__hpp		*_hpp;
+	struct acpi_php_slot	*slots;
+	struct pci_resource 	*tmem_head;	/* total from crs	*/
+	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
+	struct pci_resource 	*tio_head;	/* total from crs	*/
+	struct pci_resource 	*tbus_head;	/* total from crs	*/
+	struct pci_resource 	*mem_head;	/* available	*/
+	struct pci_resource 	*p_mem_head;	/* available	*/
+	struct pci_resource 	*io_head;	/* available	*/
+	struct pci_resource 	*bus_head;	/* available	*/
+	int scanned;
+	int type;
+};
+
+static struct acpi_bridge *acpi_bridges_head;
+
+static u8 * acpi_path_name( acpi_handle	handle)
+{
+	acpi_status		status;
+	static u8		path_name[ACPI_PATHNAME_MAX];
+	struct acpi_buffer	ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+	memset(path_name, 0, sizeof (path_name));
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &amp;ret_buf);
+
+	if (ACPI_FAILURE(status))
+		return NULL;
+	else
+		return path_name;	
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab);
+static void acpi_run_oshp ( struct acpi_bridge	*ab);
+
+static int acpi_add_slot_to_php_slots(
+	struct acpi_bridge	*ab,
+	int			bus_num,
+	acpi_handle		handle,
+	u32			adr,
+	u32			sun
+	)
+{
+	struct acpi_php_slot	*aps;
+	static long	samesun = -1;
+
+	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
+	if (!aps) {
+		err ("acpi_pciehprm: alloc for aps fail\n");
+		return -1;
+	}
+	memset(aps, 0, sizeof(struct acpi_php_slot));
+
+	aps-&gt;handle = handle;
+	aps-&gt;bus = bus_num;
+	aps-&gt;dev = (adr &gt;&gt; 16) &amp; 0xffff;
+	aps-&gt;fun = adr &amp; 0xffff;
+	aps-&gt;sun = sun;
+
+	aps-&gt;next = ab-&gt;slots;	/* cling to the bridge */
+	aps-&gt;bridge = ab;
+	ab-&gt;slots = aps;
+
+	ab-&gt;scanned += 1;
+	if (!ab-&gt;_hpp)
+		acpi_get__hpp(ab);
+
+	acpi_run_oshp(ab);
+
+	if (sun != samesun) {
+		info("acpi_pciehprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", 
+			aps-&gt;sun, ab-&gt;seg, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+		samesun = sun;
+	}
+	return 0;
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			nui[4];
+	struct acpi_buffer	ret_buf = { 0, NULL};
+	union acpi_object	*ext_obj, *package;
+	u8			*path_name = acpi_path_name(ab-&gt;handle);
+	int			i, len = 0;
+
+	/* get _hpp */
+	status = acpi_evaluate_object(ab-&gt;handle, METHOD_NAME__HPP, NULL, &amp;ret_buf);
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
+		if (!ret_buf.pointer) {
+			err ("acpi_pciehprm:%s alloc for _HPP fail\n", path_name);
+			return;
+		}
+		status = acpi_evaluate_object(ab-&gt;handle, METHOD_NAME__HPP, NULL, &amp;ret_buf);
+		if (ACPI_SUCCESS(status))
+			break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_pciehprm:%s _HPP fail=0x%x\n", path_name, status);
+			return;
+		}
+	}
+
+	ext_obj = (union acpi_object *) ret_buf.pointer;
+	if (ext_obj-&gt;type != ACPI_TYPE_PACKAGE) {
+		err ("acpi_pciehprm:%s _HPP obj not a package\n", path_name);
+		goto free_and_return;
+	}
+
+	len = ext_obj-&gt;package.count;
+	package = (union acpi_object *) ret_buf.pointer;
+	for ( i = 0; (i &lt; len) || (i &lt; 4); i++) {
+		ext_obj = (union acpi_object *) &amp;package-&gt;package.elements[i];
+		switch (ext_obj-&gt;type) {
+		case ACPI_TYPE_INTEGER:
+			nui[i] = (u8)ext_obj-&gt;integer.value;
+			break;
+		default:
+			err ("acpi_pciehprm:%s _HPP obj type incorrect\n", path_name);
+			goto free_and_return;
+		}
+	}
+
+	ab-&gt;_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	memset(ab-&gt;_hpp, 0, sizeof(struct acpi__hpp));
+
+	ab-&gt;_hpp-&gt;cache_line_size	= nui[0];
+	ab-&gt;_hpp-&gt;latency_timer		= nui[1];
+	ab-&gt;_hpp-&gt;enable_serr		= nui[2];
+	ab-&gt;_hpp-&gt;enable_perr		= nui[3];
+
+	dbg("  _HPP: cache_line_size=0x%x\n", ab-&gt;_hpp-&gt;cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", ab-&gt;_hpp-&gt;latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_perr);
+
+free_and_return:
+	kfree(ret_buf.pointer);
+}
+
+static void acpi_run_oshp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(ab-&gt;handle);
+	struct acpi_buffer	ret_buf = { 0, NULL};
+
+	/* run OSHP */
+	status = acpi_evaluate_object(ab-&gt;handle, METHOD_NAME_OSHP, NULL, &amp;ret_buf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
+	} else
+		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
+	return;
+}
+
+static acpi_status acpi_evaluate_crs(
+	acpi_handle		handle,
+	struct acpi_resource	**retbuf
+	)
+{
+	acpi_status		status;
+	struct acpi_buffer	crsbuf;
+	u8			*path_name = acpi_path_name(handle);
+
+	crsbuf.length  = 0;
+	crsbuf.pointer = NULL;
+
+	status = acpi_get_current_resources (handle, &amp;crsbuf);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		break;		/* found */
+	case AE_NOT_FOUND:
+		dbg("acpi_pciehprm:%s _CRS not found\n", path_name);
+		return status;
+	default:
+		err ("acpi_pciehprm:%s _CRS fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
+	if (!crsbuf.pointer) {
+		err ("acpi_pciehprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
+		return AE_NO_MEMORY;
+	}
+
+	status = acpi_get_current_resources (handle, &amp;crsbuf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm: %s _CRS fail=0x%x.\n", path_name, status);
+		kfree(crsbuf.pointer);
+		return status;
+	}
+
+	*retbuf = crsbuf.pointer;
+
+	return status;
+}
+
+static void free_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res, *next;
+
+	for (res = aprh; res; res = next) {
+		next = res-&gt;next;
+		kfree(res);
+	}
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res-&gt;next)
+		dbg("        base= 0x%x length= 0x%x\n", res-&gt;base, res-&gt;length);
+}
+
+static void print_slot_resources( struct acpi_php_slot	*aps)
+{
+	if (aps-&gt;bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (aps-&gt;bus_head);
+	}
+
+	if (aps-&gt;io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (aps-&gt;io_head);
+	}
+
+	if (aps-&gt;mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (aps-&gt;mem_head);
+	}
+
+	if (aps-&gt;p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (aps-&gt;p_mem_head);
+	}
+}
+
+static void print_pci_resources( struct acpi_bridge	*ab)
+{
+	if (ab-&gt;tbus_head) {
+		dbg("    Total BUS Resources:\n");
+		print_pci_resource (ab-&gt;tbus_head);
+	}
+	if (ab-&gt;bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (ab-&gt;bus_head);
+	}
+
+	if (ab-&gt;tio_head) {
+		dbg("    Total IO Resources:\n");
+		print_pci_resource (ab-&gt;tio_head);
+	}
+	if (ab-&gt;io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (ab-&gt;io_head);
+	}
+
+	if (ab-&gt;tmem_head) {
+		dbg("    Total MEM Resources:\n");
+		print_pci_resource (ab-&gt;tmem_head);
+	}
+	if (ab-&gt;mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (ab-&gt;mem_head);
+	}
+
+	if (ab-&gt;tp_mem_head) {
+		dbg("    Total PMEM Resources:\n");
+		print_pci_resource (ab-&gt;tp_mem_head);
+	}
+	if (ab-&gt;p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (ab-&gt;p_mem_head);
+	}
+	if (ab-&gt;_hpp) {
+		dbg("    _HPP: cache_line_size=0x%x\n", ab-&gt;_hpp-&gt;cache_line_size);
+		dbg("    _HPP: latency timer  =0x%x\n", ab-&gt;_hpp-&gt;latency_timer);
+		dbg("    _HPP: enable SERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_serr);
+		dbg("    _HPP: enable PERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_perr);
+	}
+}
+
+static int pciehprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if (res-&gt;base &gt; base)
+			continue;
+
+		if ((res-&gt;base + res-&gt;length) &lt; (base + size))
+			continue;
+
+		if (res-&gt;base &lt; base) {
+			tbase = base;
+
+			if ((res-&gt;length - (tbase - res-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base;
+			split_node-&gt;length = tbase - res-&gt;base;
+			res-&gt;base = tbase;
+			res-&gt;length -= split_node-&gt;length;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (res-&gt;length &gt;= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base + size;
+			split_node-&gt;length = res-&gt;length - size;
+			res-&gt;length = size;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res-&gt;next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode-&gt;next != res)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = res-&gt;next;
+		}
+		res-&gt;next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int pciehprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res-&gt;next)
+		pciehprm_delete_resource(aprh, res-&gt;base, res-&gt;length);
+
+	return 0;
+}
+
+static int pciehprm_add_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if ((res-&gt;base + res-&gt;length) == base) {
+			res-&gt;length += size;
+			size = 0L;
+			break;
+		}
+		if (res-&gt;next == *aprh)
+			break;
+	}
+
+	if (size) {
+		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		if (!res) {
+			err ("acpi_pciehprm: alloc for res fail\n");
+			return -ENOMEM;
+		}
+		memset(res, 0, sizeof (struct pci_resource));
+
+		res-&gt;base = base;
+		res-&gt;length = size;
+		res-&gt;next = *aprh;
+		*aprh = res;
+	}
+
+	return 0;
+}
+
+static int pciehprm_add_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+	int	rc = 0;
+
+	for (res = this; res &amp;&amp; !rc; res = res-&gt;next)
+		rc = pciehprm_add_resource(aprh, res-&gt;base, res-&gt;length);
+
+	return rc;
+}
+
+static void acpi_parse_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_io	*dataio;
+	dataio = (struct acpi_resource_io *) data;
+
+	dbg("Io Resource\n");
+	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio-&gt;io_decode ? 16:10);
+	dbg("  Range minimum base: %08X\n", dataio-&gt;min_base_address);
+	dbg("  Range maximum base: %08X\n", dataio-&gt;max_base_address);
+	dbg("  Alignment: %08X\n", dataio-&gt;alignment);
+	dbg("  Range Length: %08X\n", dataio-&gt;range_length);
+}
+
+static void acpi_parse_fixed_io (
+	struct acpi_bridge	*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_fixed_io  *datafio;
+	datafio = (struct acpi_resource_fixed_io *) data;
+
+	dbg("Fixed Io Resource\n");
+	dbg("  Range base address: %08X", datafio-&gt;base_address);
+	dbg("  Range length: %08X", datafio-&gt;range_length);
+}
+
+static void acpi_parse_address16_32 (
+	struct acpi_bridge	*ab,
+	union acpi_resource_data	*data,
+	acpi_resource_type	id
+	)
+{
+	/* 
+	 * acpi_resource_address16 == acpi_resource_address32
+	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
+	 */
+	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
+	struct pci_resource **aprh, **tprh;
+
+	if (id == ACPI_RSTYPE_ADDRESS16)
+		dbg("acpi_pciehprm:16-Bit Address Space Resource\n");
+	else
+		dbg("acpi_pciehprm:32-Bit Address Space Resource\n");
+
+	switch (data32-&gt;resource_type) {
+	case ACPI_MEMORY_RANGE: 
+		dbg("  Resource Type: Memory Range\n");
+		aprh = &amp;ab-&gt;mem_head;
+		tprh = &amp;ab-&gt;tmem_head;
+
+		switch (data32-&gt;attribute.memory.cache_attribute) {
+		case ACPI_NON_CACHEABLE_MEMORY:
+			dbg("  Type Specific: Noncacheable memory\n");
+			break; 
+		case ACPI_CACHABLE_MEMORY:
+			dbg("  Type Specific: Cacheable memory\n");
+			break; 
+		case ACPI_WRITE_COMBINING_MEMORY:
+			dbg("  Type Specific: Write-combining memory\n");
+			break; 
+		case ACPI_PREFETCHABLE_MEMORY:
+			aprh = &amp;ab-&gt;p_mem_head;
+			dbg("  Type Specific: Prefetchable memory\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid cache attribute\n");
+			break;
+		}
+
+		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32-&gt;attribute.memory.read_write_attribute ? "/Write":" Only");
+		break;
+
+	case ACPI_IO_RANGE: 
+		dbg("  Resource Type: I/O Range\n");
+		aprh = &amp;ab-&gt;io_head;
+		tprh = &amp;ab-&gt;tio_head;
+
+		switch (data32-&gt;attribute.io.range_attribute) {
+		case ACPI_NON_ISA_ONLY_RANGES:
+			dbg("  Type Specific: Non-ISA Io Addresses\n");
+			break; 
+		case ACPI_ISA_ONLY_RANGES:
+			dbg("  Type Specific: ISA Io Addresses\n");
+			break; 
+		case ACPI_ENTIRE_RANGE:
+			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid range attribute\n");
+			break;
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE: 
+		dbg("  Resource Type: Bus Number Range(fixed)\n");
+		/* fixup to be compatible with the rest of php driver */
+		data32-&gt;min_address_range++;
+		data32-&gt;address_length--;
+		aprh = &amp;ab-&gt;bus_head;
+		tprh = &amp;ab-&gt;tbus_head;
+		break; 
+	default: 
+		dbg("  Resource Type: Invalid resource type. Exiting.\n");
+		return;
+	}
+
+	dbg("  Resource %s\n", ACPI_CONSUMER == data32-&gt;producer_consumer ? "Consumer":"Producer");
+	dbg("  %s decode\n", ACPI_SUB_DECODE == data32-&gt;decode ? "Subtractive":"Positive");
+	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32-&gt;min_address_fixed ? "":"not");
+	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32-&gt;max_address_fixed ? "":"not");
+	dbg("  Granularity: %08X\n", data32-&gt;granularity);
+	dbg("  Address range min: %08X\n", data32-&gt;min_address_range);
+	dbg("  Address range max: %08X\n", data32-&gt;max_address_range);
+	dbg("  Address translation offset: %08X\n", data32-&gt;address_translation_offset);
+	dbg("  Address Length: %08X\n", data32-&gt;address_length);
+
+	if (0xFF != data32-&gt;resource_source.index) {
+		dbg("  Resource Source Index: %X\n", data32-&gt;resource_source.index);
+		/* dbg("  Resource Source: %s\n", data32-&gt;resource_source.string_ptr); */
+	}
+
+	pciehprm_add_resource(aprh, data32-&gt;min_address_range, data32-&gt;address_length);
+}
+
+static acpi_status acpi_parse_crs(
+	struct acpi_bridge	*ab,
+	struct acpi_resource	*crsbuf
+	)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_resource	*resource = crsbuf;
+	u8				count = 0;
+	u8				done = 0;
+
+	while (!done) {
+		dbg("acpi_pciehprm: PCI bus 0x%x Resource structure %x.\n", ab-&gt;bus, count++);
+		switch (resource-&gt;id) {
+		case ACPI_RSTYPE_IRQ:
+			dbg("Irq -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_DMA:
+			dbg("DMA -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_START_DPF:
+			dbg("Start DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_DPF:
+			dbg("End DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_IO:
+			acpi_parse_io (ab, &amp;resource-&gt;data);
+			break; 
+		case ACPI_RSTYPE_FIXED_IO:
+			acpi_parse_fixed_io (ab, &amp;resource-&gt;data);
+			break; 
+		case ACPI_RSTYPE_VENDOR:
+			dbg("Vendor -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_TAG:
+			dbg("End_tag -------- Resource\n");
+			done = 1;
+			break; 
+		case ACPI_RSTYPE_MEM24:
+			dbg("Mem24 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_MEM32:
+			dbg("Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_FIXED_MEM32:
+			dbg("Fixed Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_ADDRESS16:
+			acpi_parse_address16_32(ab, &amp;resource-&gt;data, ACPI_RSTYPE_ADDRESS16);
+			break; 
+		case ACPI_RSTYPE_ADDRESS32:
+			acpi_parse_address16_32(ab, &amp;resource-&gt;data, ACPI_RSTYPE_ADDRESS32);
+			break; 
+		case ACPI_RSTYPE_ADDRESS64:
+			info("Address64 -------- Resource unparsed\n");
+			break; 
+		case ACPI_RSTYPE_EXT_IRQ:
+			dbg("Ext Irq -------- Resource\n");
+			break; 
+		default:
+			dbg("Invalid -------- resource type 0x%x\n", resource-&gt;id);
+			break;
+		}
+
+		resource = (struct acpi_resource *) ((char *)resource + resource-&gt;length);
+	}
+
+	return status;
+}
+
+static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	struct acpi_resource	*crsbuf;
+
+	status = acpi_evaluate_crs(ab-&gt;handle, &amp;crsbuf);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_parse_crs(ab, crsbuf);
+		kfree(crsbuf);
+
+		pciehp_resource_sort_and_combine(&amp;ab-&gt;bus_head);
+		pciehp_resource_sort_and_combine(&amp;ab-&gt;io_head);
+		pciehp_resource_sort_and_combine(&amp;ab-&gt;mem_head);
+		pciehp_resource_sort_and_combine(&amp;ab-&gt;p_mem_head);
+
+		pciehprm_add_resources (&amp;ab-&gt;tbus_head, ab-&gt;bus_head);
+		pciehprm_add_resources (&amp;ab-&gt;tio_head, ab-&gt;io_head);
+		pciehprm_add_resources (&amp;ab-&gt;tmem_head, ab-&gt;mem_head);
+		pciehprm_add_resources (&amp;ab-&gt;tp_mem_head, ab-&gt;p_mem_head);
+	}
+
+	return status;
+}
+
+/* find acpi_bridge downword from ab.  */
+static struct acpi_bridge *
+find_acpi_bridge_by_bus(
+	struct acpi_bridge *ab,
+	int seg,
+	int bus		/* pdev-&gt;subordinate-&gt;number */
+	)
+{
+	struct acpi_bridge	*lab = NULL;
+
+	if (!ab)
+		return NULL;
+
+	if ((ab-&gt;bus == bus) &amp;&amp; (ab-&gt;seg == seg))
+		return ab;
+
+	if (ab-&gt;child)
+		lab = find_acpi_bridge_by_bus(ab-&gt;child, seg, bus);
+
+	if (!lab)
+	if (ab-&gt;next)
+		lab = find_acpi_bridge_by_bus(ab-&gt;next, seg, bus);
+
+	return lab;
+}
+
+/*
+ * Build a device tree of ACPI PCI Bridges
+ */
+static void pciehprm_acpi_register_a_bridge (
+	struct acpi_bridge	**head,
+	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
+	struct acpi_bridge	*cab	/* child bridge to add */
+	)
+{
+	struct acpi_bridge	*lpab;
+	struct acpi_bridge	*lcab;
+
+	lpab = find_acpi_bridge_by_bus(*head, pab-&gt;seg, pab-&gt;bus);
+	if (!lpab) {
+		if (!(pab-&gt;type &amp; BRIDGE_TYPE_HOST))
+			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab-&gt;seg, pab-&gt;bus);
+		pab-&gt;next = *head;
+		*head = pab;
+		lpab = pab;
+	}
+
+	if ((cab-&gt;type &amp; BRIDGE_TYPE_HOST) &amp;&amp; (pab == cab))
+		return;
+
+	lcab = find_acpi_bridge_by_bus(*head, cab-&gt;seg, cab-&gt;bus);
+	if (lcab) {
+		if ((pab-&gt;bus != lcab-&gt;parent-&gt;bus) || (lcab-&gt;bus != cab-&gt;bus))
+			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab-&gt;seg, cab-&gt;bus);
+		return;
+	} else
+		lcab = cab;
+
+	lcab-&gt;parent = lpab;
+	lcab-&gt;next = lpab-&gt;child;
+	lpab-&gt;child = lcab;
+}
+
+static acpi_status pciehprm_acpi_build_php_slots_callback(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	ulong		bus_num;
+	ulong		seg_num;
+	ulong		sun, adr;
+	ulong		padr = 0;
+	acpi_handle		phandle = NULL;
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*lab;
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get _SUN */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &amp;sun);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_pciehprm:%s _SUN fail=0x%x\n", path_name, status);
+			return status;
+		}
+	}
+
+	/* get _ADR. _ADR must exist if _SUN exists */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &amp;adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	dbg("acpi_pciehprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
+
+	status = acpi_get_parent(handle, &amp;phandle);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s get_parent fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	bus_num = pab-&gt;bus;
+	seg_num = pab-&gt;seg;
+
+	if (pab-&gt;bus == bus_num) {
+		lab = pab;
+	} else {
+		dbg("WARN: pab is not parent\n");
+		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
+		if (!lab) {
+			dbg("acpi_pciehprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
+			if (!lab) {
+				err("acpi_pciehprm: alloc for ab fail\n");
+				return AE_NO_MEMORY;
+			}
+			memset(lab, 0, sizeof(struct acpi_bridge));
+
+			lab-&gt;handle = phandle;
+			lab-&gt;pbus = pab-&gt;bus;
+			lab-&gt;pdevice = (int)(padr &gt;&gt; 16) &amp; 0xffff;
+			lab-&gt;pfunction = (int)(padr &amp; 0xffff);
+			lab-&gt;bus = (int)bus_num;
+			lab-&gt;scanned = 0;
+			lab-&gt;type = BRIDGE_TYPE_P2P;
+
+			pciehprm_acpi_register_a_bridge (&amp;acpi_bridges_head, pab, lab);
+		} else
+			dbg("acpi_pciehprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+	}
+
+	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
+
+	return (status);
+}
+
+static int pciehprm_acpi_build_php_slots(
+	struct acpi_bridge	*ab,
+	u32			depth
+	)
+{
+	acpi_status	status;
+	u8		*path_name = acpi_path_name(ab-&gt;handle);
+
+	/* Walk down this pci bridge to get _SUNs if any behind P2P */
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+				ab-&gt;handle,
+				depth,
+				pciehprm_acpi_build_php_slots_callback,
+				ab,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		dbg("acpi_pciehprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab-&gt;seg, ab-&gt;bus, status);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void build_a_bridge(
+	struct acpi_bridge	*pab,
+	struct acpi_bridge	*ab
+	)
+{
+	u8		*path_name = acpi_path_name(ab-&gt;handle);
+
+	pciehprm_acpi_register_a_bridge (&amp;acpi_bridges_head, pab, ab);
+
+	switch (ab-&gt;type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("acpi_pciehprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab-&gt;bus, ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction, path_name);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("acpi_pciehprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab-&gt;pbus, ab-&gt;bus, ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction, path_name);
+		break;
+	};
+
+	/* build any immediate PHP slots under this pci bridge */
+	pciehprm_acpi_build_php_slots(ab, 1);
+}
+
+static struct acpi_bridge * add_p2p_bridge(
+	acpi_handle handle,
+	struct acpi_bridge	*pab,	/* parent */
+	ulong	adr
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_dev	*pdev;
+	ulong		devnum, funcnum;
+	u8			*path_name = acpi_path_name(handle);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_pciehprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	devnum = (adr &gt;&gt; 16) &amp; 0xffff;
+	funcnum = adr &amp; 0xffff;
+
+	pdev = pci_find_slot(pab-&gt;bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev || !pdev-&gt;subordinate) {
+		err("acpi_pciehprm:%s is not a P2P Bridge\n", path_name);
+		kfree(ab);
+		return NULL;
+	}
+
+	ab-&gt;handle = handle;
+	ab-&gt;seg = pab-&gt;seg;
+	ab-&gt;pbus = pab-&gt;bus;		/* or pdev-&gt;bus-&gt;number */
+	ab-&gt;pdevice = devnum;		/* or PCI_SLOT(pdev-&gt;devfn) */
+	ab-&gt;pfunction = funcnum;	/* or PCI_FUNC(pdev-&gt;devfn) */
+	ab-&gt;bus = pdev-&gt;subordinate-&gt;number;
+	ab-&gt;scanned = 0;
+	ab-&gt;type = BRIDGE_TYPE_P2P;
+
+	dbg("acpi_pciehprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
+		pab-&gt;bus, ab-&gt;bus, pdev-&gt;bus-&gt;number, PCI_SLOT(pdev-&gt;devfn), PCI_FUNC(pdev-&gt;devfn),
+		pab-&gt;bus, (u32)devnum, (u32)funcnum, path_name);
+
+	build_a_bridge(pab, ab);
+
+	return ab;
+}
+
+static acpi_status scan_p2p_bridge(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*ab;
+	acpi_status		status;
+	ulong			adr = 0;
+	u8			*path_name = acpi_path_name(handle);
+	ulong			devnum, funcnum;
+	struct pci_dev		*pdev;
+
+	/* get device, function */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &amp;adr);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return AE_OK;
+	}
+
+	devnum = (adr &gt;&gt; 16) &amp; 0xffff;
+	funcnum = adr &amp; 0xffff;
+
+	pdev = pci_find_slot(pab-&gt;bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev)
+		return AE_OK;
+	if (!pdev-&gt;subordinate)
+		return AE_OK;
+
+	ab = add_p2p_bridge(handle, pab, adr);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					(u32)1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static struct acpi_bridge * add_host_bridge(
+	acpi_handle handle,
+	ulong	segnum,
+	ulong	busnum
+	)
+{
+	ulong			adr = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get device, function: host br adr is always 0000 though.  */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &amp;adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s _ADR fail=0x%x\n", path_name, status);
+		return NULL;
+	}
+	dbg("acpi_pciehprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, 
+		(u32)busnum, (u32)(adr &gt;&gt; 16) &amp; 0xffff, (u32)adr &amp; 0xffff, path_name);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_pciehprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	ab-&gt;handle = handle;
+	ab-&gt;seg = (int)segnum;
+	ab-&gt;bus = ab-&gt;pbus = (int)busnum;
+	ab-&gt;pdevice = (int)(adr &gt;&gt; 16) &amp; 0xffff;
+	ab-&gt;pfunction = (int)(adr &amp; 0xffff);
+	ab-&gt;scanned = 0;
+	ab-&gt;type = BRIDGE_TYPE_HOST;
+
+	/* get root pci bridge's current resources */
+	status = acpi_get_crs(ab);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
+		kfree(ab);
+		return NULL;
+	}
+	build_a_bridge(ab, ab);
+
+	return ab;
+}
+
+static acpi_status acpi_scan_from_root_pci_callback (
+	acpi_handle	handle,
+	u32			Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		segnum = 0;
+	ulong		busnum = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &amp;segnum);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			err("acpi_pciehprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
+			return status;
+		}
+		segnum = 0;
+	}
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &amp;busnum);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	ab = add_host_bridge(handle, segnum, busnum);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_pciehprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static int pciehprm_acpi_scan_pci (void)
+{
+	acpi_status	status;
+
+	/*
+	 * TBD: traverse LDM device tree with the help of
+	 *  unified ACPI augmented for php device population.
+	 */
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_scan_from_root_pci_callback,
+				NULL,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:get_device PCI ROOT HID fail=0x%x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+int pciehprm_init(enum php_ctlr_type ctlr_type)
+{
+	int	rc;
+
+	if (ctlr_type != PCI)
+		return -ENODEV;
+
+	dbg("pciehprm ACPI init &lt;enter&gt;\n");
+	acpi_bridges_head = NULL;
+
+	/* construct PCI bus:device tree of acpi_handles */
+	rc = pciehprm_acpi_scan_pci();
+	if (rc)
+		return rc;
+
+	dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success");
+	return rc;
+}
+
+static void free_a_slot(struct acpi_php_slot *aps)
+{
+	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps-&gt;sun, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+
+	free_pci_resource (aps-&gt;io_head);
+	free_pci_resource (aps-&gt;bus_head);
+	free_pci_resource (aps-&gt;mem_head);
+	free_pci_resource (aps-&gt;p_mem_head);
+
+	kfree(aps);
+}
+
+static void free_a_bridge( struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps, *next;
+
+	switch (ab-&gt;type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab-&gt;bus, acpi_path_name(ab-&gt;handle), ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab-&gt;pbus, ab-&gt;bus, acpi_path_name(ab-&gt;handle), ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction);
+		break;
+	};
+
+	/* free slots first */
+	for (aps = ab-&gt;slots; aps; aps = next) {
+		next = aps-&gt;next;
+		free_a_slot(aps);
+	}
+
+	free_pci_resource (ab-&gt;io_head);
+	free_pci_resource (ab-&gt;tio_head);
+	free_pci_resource (ab-&gt;bus_head);
+	free_pci_resource (ab-&gt;tbus_head);
+	free_pci_resource (ab-&gt;mem_head);
+	free_pci_resource (ab-&gt;tmem_head);
+	free_pci_resource (ab-&gt;p_mem_head);
+	free_pci_resource (ab-&gt;tp_mem_head);
+
+	kfree(ab);
+}
+
+static void pciehprm_free_bridges ( struct acpi_bridge	*ab)
+{
+	if (ab-&gt;child)
+		pciehprm_free_bridges (ab-&gt;child);
+
+	if (ab-&gt;next)
+		pciehprm_free_bridges (ab-&gt;next);
+
+	free_a_bridge(ab);
+}
+
+void pciehprm_cleanup(void)
+{
+	pciehprm_free_bridges (acpi_bridges_head);
+}
+
+static int get_number_of_slots (
+	struct acpi_bridge	*ab,
+	int				selfonly
+	)
+{
+	struct acpi_php_slot	*aps;
+	int	prev_slot = -1;
+	int	slot_num = 0;
+
+	for ( aps = ab-&gt;slots; aps; aps = aps-&gt;next)
+		if (aps-&gt;dev != prev_slot) {
+			prev_slot = aps-&gt;dev;
+			slot_num++;
+		}
+
+	if (ab-&gt;child)
+		slot_num += get_number_of_slots (ab-&gt;child, 0);
+
+	if (selfonly)
+		return slot_num;
+
+	if (ab-&gt;next)
+		slot_num += get_number_of_slots (ab-&gt;next, 0);
+
+	return slot_num;
+}
+
+static int print_acpi_resources (struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot		*aps;
+	int	i;
+
+	switch (ab-&gt;type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("PCI HOST Bridge (%x) [%s]\n", ab-&gt;bus, acpi_path_name(ab-&gt;handle));
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab-&gt;pbus, ab-&gt;bus, acpi_path_name(ab-&gt;handle));
+		break;
+	};
+
+	print_pci_resources (ab);
+
+	for ( i = -1, aps = ab-&gt;slots; aps; aps = aps-&gt;next) {
+		if (aps-&gt;dev == i)
+			continue;
+		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps-&gt;sun, aps-&gt;seg, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+		print_slot_resources(aps);
+		i = aps-&gt;dev;
+	}
+
+	if (ab-&gt;child)
+		print_acpi_resources (ab-&gt;child);
+
+	if (ab-&gt;next)
+		print_acpi_resources (ab-&gt;next);
+
+	return 0;
+}
+
+int pciehprm_print_pirt(void)
+{
+	dbg("PCIEHPRM ACPI Slots\n");
+	print_acpi_resources (acpi_bridges_head);
+
+	return 0;
+}
+
+static struct acpi_php_slot * get_acpi_slot (
+	struct acpi_bridge *ab,
+	u32 sun
+	)
+{
+	struct acpi_php_slot	*aps = NULL;
+
+	for ( aps = ab-&gt;slots; aps; aps = aps-&gt;next)
+		if (aps-&gt;sun == sun)
+			return aps;
+
+	if (!aps &amp;&amp; ab-&gt;child) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab-&gt;child, sun);
+		if (aps)
+			return aps;
+	}
+
+	if (!aps &amp;&amp; ab-&gt;next) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab-&gt;next, sun);
+		if (aps)
+			return aps;
+	}
+
+	return aps;
+
+}
+
+void * pciehprm_get_slot(struct slot *slot)
+{
+	struct acpi_bridge	*ab = acpi_bridges_head;
+	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot-&gt;number);
+
+	aps-&gt;slot = slot;
+
+	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps-&gt;sun, aps-&gt;seg, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+
+	return (void *)aps;
+}
+
+static void pciehprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func-&gt;bus_head);
+	}
+	if (func-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func-&gt;io_head);
+	}
+	if (func-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func-&gt;mem_head);
+	}
+	if (func-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func-&gt;p_mem_head);
+	}
+}
+
+static void pciehprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl-&gt;bus_head);
+	}
+	if (ctrl-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl-&gt;io_head);
+	}
+	if (ctrl-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl-&gt;mem_head);
+	}
+	if (ctrl-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl-&gt;p_mem_head);
+	}
+}
+
+static int pciehprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = pciehprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = pciehprm_delete_resources (&amp;ctrl-&gt;bus_head, func-&gt;bus_head);
+		rc |= pciehprm_delete_resources (&amp;ctrl-&gt;io_head, func-&gt;io_head);
+		rc |= pciehprm_delete_resources (&amp;ctrl-&gt;mem_head, func-&gt;mem_head);
+		rc |= pciehprm_delete_resources (&amp;ctrl-&gt;p_mem_head, func-&gt;p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl-&gt;slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn &lt; 32; devn++) {
+		for (funn = 0; funn &lt; 8; funn++) {
+			/*
+			if (devn == ctrl-&gt;device &amp;&amp; funn == ctrl-&gt;function)
+				continue;
+			*/
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+			pci_bus_read_config_dword(ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &amp;vid);
+
+			if (vid != 0xFFFFFFFF) {
+				dbg("%s: vid = %x\n", __FUNCTION__, vid);
+				func = pciehp_slot_find(busn, devn, funn);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl-&gt;bus);
+				pciehprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources(
+	struct controller 	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int		status = 0;
+
+	if (ab-&gt;bus_head) {
+		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = pciehprm_add_resources (&amp;ctrl-&gt;bus_head, ab-&gt;bus_head);
+		if (pciehprm_delete_resources (&amp;ab-&gt;bus_head, ctrl-&gt;bus_head))
+			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	if (ab-&gt;io_head) {
+		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = pciehprm_add_resources (&amp;ctrl-&gt;io_head, ab-&gt;io_head);
+		if (pciehprm_delete_resources (&amp;ab-&gt;io_head, ctrl-&gt;io_head))
+			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	if (ab-&gt;mem_head) {
+		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = pciehprm_add_resources (&amp;ctrl-&gt;mem_head, ab-&gt;mem_head);
+		if (pciehprm_delete_resources (&amp;ab-&gt;mem_head, ctrl-&gt;mem_head))
+			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	if (ab-&gt;p_mem_head) {
+		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = pciehprm_add_resources (&amp;ctrl-&gt;p_mem_head, ab-&gt;p_mem_head);
+		if (pciehprm_delete_resources (&amp;ab-&gt;p_mem_head, ctrl-&gt;p_mem_head))
+			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	return status;
+}
+
+static int no_pci_resources( struct acpi_bridge *ab)
+{
+	return !(ab-&gt;p_mem_head || ab-&gt;mem_head || ab-&gt;io_head || ab-&gt;bus_head);
+}
+
+static int find_pci_bridge_resources (
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+	struct pci_func func;
+
+	memset(&amp;func, 0, sizeof(struct pci_func));
+
+	func.bus = ab-&gt;pbus;
+	func.device = ab-&gt;pdevice;
+	func.function = ab-&gt;pfunction;
+	func.is_a_board = 1;
+
+	/* Get used resources for this PCI bridge */
+	rc = pciehp_save_used_resources (ctrl, &amp;func, !DISABLE_CARD);
+
+	ab-&gt;io_head = func.io_head;
+	ab-&gt;mem_head = func.mem_head;
+	ab-&gt;p_mem_head = func.p_mem_head;
+	ab-&gt;bus_head = func.bus_head;
+	if (ab-&gt;bus_head)
+		pciehprm_delete_resource(&amp;ab-&gt;bus_head, ctrl-&gt;pci_dev-&gt;subordinate-&gt;number, 1);
+
+	return rc;
+}
+
+static int get_pci_resources_from_bridge(
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+
+	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl-&gt;bus, ab-&gt;bus);
+
+	rc = find_pci_bridge_resources (ctrl, ab);
+
+	pciehp_resource_sort_and_combine(&amp;ab-&gt;bus_head);
+	pciehp_resource_sort_and_combine(&amp;ab-&gt;io_head);
+	pciehp_resource_sort_and_combine(&amp;ab-&gt;mem_head);
+	pciehp_resource_sort_and_combine(&amp;ab-&gt;p_mem_head);
+
+	pciehprm_add_resources (&amp;ab-&gt;tbus_head, ab-&gt;bus_head);
+	pciehprm_add_resources (&amp;ab-&gt;tio_head, ab-&gt;io_head);
+	pciehprm_add_resources (&amp;ab-&gt;tmem_head, ab-&gt;mem_head);
+	pciehprm_add_resources (&amp;ab-&gt;tp_mem_head, ab-&gt;p_mem_head);
+
+	return rc;
+}
+
+static int get_pci_resources(
+	struct controller	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	rc = 0;
+
+	if (no_pci_resources(ab)) {
+		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab-&gt;bus);
+		rc = get_pci_resources_from_bridge(ctrl, ab);
+	}
+
+	return rc;
+}
+
+/*
+ * Get resources for this ctrl.
+ *  1. get total resources from ACPI _CRS or bridge (this ctrl)
+ *  2. find used resources of existing adapters
+ *	3. subtract used resources from total resources
+ */
+int pciehprm_find_available_resources( struct controller *ctrl)
+{
+	int rc = 0;
+	struct acpi_bridge	*ab;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl-&gt;seg, ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+	if (!ab) {
+		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+		return -1;
+	}
+	if (no_pci_resources(ab)) {
+		rc = get_pci_resources(ctrl, ab);
+		if (rc) {
+			err("pfar:cannot get pci resources of PCI 0x%x.\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+			return -1;
+		}
+	}
+
+	rc = bind_pci_resources(ctrl, ab);
+	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+	pciehprm_dump_ctrl_res(ctrl);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+	pciehprm_dump_ctrl_res(ctrl);
+
+	return rc;
+}
+
+int pciehprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_bus lpci_bus, *pci_bus;
+	int				rc = 0;
+	unsigned int	devfn;
+	u8				cls= 0x08;	/* default cache line size	*/
+	u8				lt = 0x40;	/* default latency timer	*/
+	u8				ep = 0;
+	u8				es = 0;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl-&gt;seg, ctrl-&gt;bus);
+
+	if (ab) {
+		if (ab-&gt;_hpp) {
+			lt  = (u8)ab-&gt;_hpp-&gt;latency_timer;
+			cls = (u8)ab-&gt;_hpp-&gt;cache_line_size;
+			ep  = (u8)ab-&gt;_hpp-&gt;enable_perr;
+			es  = (u8)ab-&gt;_hpp-&gt;enable_serr;
+		} else
+			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+	} else
+		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
+	}
+
+	/* set base Latency Timer */
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
+	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
+
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
+	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
+
+	return rc;
+}
+
+void pciehprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, cmd, bcommand, bcmd;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct acpi_bridge	*ab;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &amp;command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;bcommand);
+	}
+
+	cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl-&gt;seg, ctrl-&gt;bus);
+	if (ab) {
+		if (ab-&gt;_hpp) {
+			if (ab-&gt;_hpp-&gt;enable_perr) {
+				command |= PCI_COMMAND_PARITY;
+				bcommand |= PCI_BRIDGE_CTL_PARITY;
+			} else {
+				command &amp;= ~PCI_COMMAND_PARITY;
+				bcommand &amp;= ~PCI_BRIDGE_CTL_PARITY;
+			}
+			if (ab-&gt;_hpp-&gt;enable_serr) {
+				command |= PCI_COMMAND_SERR;
+				bcommand |= PCI_BRIDGE_CTL_SERR;
+			} else {
+				command &amp;= ~PCI_COMMAND_SERR;
+				bcommand &amp;= ~PCI_BRIDGE_CTL_SERR;
+			}
+		} else
+			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+	} else
+		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+
+	if (command != cmd) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+	}
+	if ((card_type == PCI_HEADER_TYPE_BRIDGE) &amp;&amp; (bcommand != bcmd)) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
diff -puN /dev/null drivers/pci/hotplug/pciehprm.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehprm.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,53 @@
+/*
+ * PCIEHPRM : PCIEHP Resource Manager for ACPI/non-ACPI platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#ifndef _PCIEHPRM_H_
+#define _PCIEHPRM_H_
+
+#ifdef	CONFIG_HOTPLUG_PCI_PCIE_PHPRM_NONACPI
+#include "pciehprm_nonacpi.h"
+#endif
+
+int pciehprm_init(enum php_ctlr_type ct);
+void pciehprm_cleanup(void);
+int pciehprm_print_pirt(void);
+void *pciehprm_get_slot(struct slot *slot);
+int pciehprm_find_available_resources(struct controller *ctrl);
+int pciehprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
+void pciehprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
+
+#ifdef	DEBUG
+#define RES_CHECK(this, bits)	\
+	{ if (((this) &amp; (bits - 1))) \
+		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
+#else
+#define RES_CHECK(this, bits)
+#endif
+
+#endif				/* _PCIEHPRM_H_ */
diff -puN /dev/null drivers/pci/hotplug/pciehprm_nonacpi.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehprm_nonacpi.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,498 @@
+/*
+ * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#ifdef CONFIG_IA64
+#include &lt;asm/iosapic.h&gt;
+#endif
+#include "pciehp.h"
+#include "pciehprm.h"
+#include "pciehprm_nonacpi.h"
+
+
+void pciehprm_cleanup(void)
+{
+	return;
+}
+
+int pciehprm_print_pirt(void)
+{
+	return 0;
+}
+
+void * pciehprm_get_slot(struct slot *slot)
+{
+	return NULL;
+}
+
+int pciehprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+
+	*sun = (u8) (ctrl-&gt;first_slot);
+	return 0;
+}
+
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res-&gt;next)
+		dbg("        base= 0x%x length= 0x%x\n", res-&gt;base, res-&gt;length);
+}
+
+
+static void phprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func-&gt;bus_head);
+	}
+	if (func-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func-&gt;io_head);
+	}
+	if (func-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func-&gt;mem_head);
+	}
+	if (func-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func-&gt;p_mem_head);
+	}
+}
+
+static int phprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return pciehp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int phprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if (res-&gt;base &gt; base)
+			continue;
+
+		if ((res-&gt;base + res-&gt;length) &lt; (base + size))
+			continue;
+
+		if (res-&gt;base &lt; base) {
+			tbase = base;
+
+			if ((res-&gt;length - (tbase - res-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base;
+			split_node-&gt;length = tbase - res-&gt;base;
+			res-&gt;base = tbase;
+			res-&gt;length -= split_node-&gt;length;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (res-&gt;length &gt;= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base + size;
+			split_node-&gt;length = res-&gt;length - size;
+			res-&gt;length = size;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res-&gt;next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode-&gt;next != res)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = res-&gt;next;
+		}
+		res-&gt;next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int phprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res-&gt;next)
+		phprm_delete_resource(aprh, res-&gt;base, res-&gt;length);
+
+	return 0;
+}
+
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = phprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = phprm_delete_resources (&amp;ctrl-&gt;bus_head, func-&gt;bus_head);
+		rc |= phprm_delete_resources (&amp;ctrl-&gt;io_head, func-&gt;io_head);
+		rc |= phprm_delete_resources (&amp;ctrl-&gt;mem_head, func-&gt;mem_head);
+		rc |= phprm_delete_resources (&amp;ctrl-&gt;p_mem_head, func-&gt;p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int pciehprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	pciehp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if (res-&gt;base &gt; base)
+			continue;
+
+		if ((res-&gt;base + res-&gt;length) &lt; (base + size))
+			continue;
+
+		if (res-&gt;base &lt; base) {
+			tbase = base;
+
+			if ((res-&gt;length - (tbase - res-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base;
+			split_node-&gt;length = tbase - res-&gt;base;
+			res-&gt;base = tbase;
+			res-&gt;length -= split_node-&gt;length;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (res-&gt;length &gt;= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base + size;
+			split_node-&gt;length = res-&gt;length - size;
+			res-&gt;length = size;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res-&gt;next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode-&gt;next != res)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = res-&gt;next;
+		}
+		res-&gt;next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl-&gt;slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn &lt; 32; devn++) {
+		for (funn = 0; funn &lt; 8; funn++) {
+			/*
+			if (devn == ctrl-&gt;device &amp;&amp; funn == ctrl-&gt;function)
+				continue;
+			*/
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+
+			pci_bus_read_config_dword(ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &amp;vid);
+
+			if (vid != 0xFFFFFFFF) {
+				dbg("%s: vid = %x bus %x dev %x fun %x\n", __FUNCTION__,
+				vid, busn, devn, funn);
+				func = pciehp_slot_find(busn, devn, funn);
+				dbg("%s: func = %p\n", __FUNCTION__,func);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl-&gt;bus);
+				phprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void phprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl-&gt;bus_head);
+	}
+	if (ctrl-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl-&gt;io_head);
+	}
+	if (ctrl-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl-&gt;mem_head);
+	}
+	if (ctrl-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl-&gt;p_mem_head);
+	}
+}
+
+/*
+ * phprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int pciehprm_find_available_resources(struct controller *ctrl)
+{
+	struct pci_func func;
+	u32 rc;
+
+	memset(&amp;func, 0, sizeof(struct pci_func));
+
+	func.bus = ctrl-&gt;bus;
+	func.device = ctrl-&gt;device;
+	func.function = ctrl-&gt;function;
+	func.is_a_board = 1;
+
+	/* Get resources for this PCI bridge */
+	rc = pciehp_save_used_resources (ctrl, &amp;func, !DISABLE_CARD);
+	dbg("%s: pciehp_save_used_resources rc = %d\n", __FUNCTION__, rc);
+
+	if (func.mem_head)
+		func.mem_head-&gt;next = ctrl-&gt;mem_head;
+	ctrl-&gt;mem_head = func.mem_head;
+
+	if (func.p_mem_head)
+		func.p_mem_head-&gt;next = ctrl-&gt;p_mem_head;
+	ctrl-&gt;p_mem_head = func.p_mem_head;
+
+	if (func.io_head)
+		func.io_head-&gt;next = ctrl-&gt;io_head;
+	ctrl-&gt;io_head = func.io_head;
+
+	if(func.bus_head)
+		func.bus_head-&gt;next = ctrl-&gt;bus_head;
+	ctrl-&gt;bus_head = func.bus_head;
+
+	if (ctrl-&gt;bus_head)
+		pciehprm_delete_resource(&amp;ctrl-&gt;bus_head, ctrl-&gt;pci_dev-&gt;subordinate-&gt;number, 1);
+	
+	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl-&gt;bus);
+	phprm_dump_ctrl_res(ctrl);
+
+	dbg("%s: before bind_pci_resources_to slots\n", __FUNCTION__);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl-&gt;bus);
+	phprm_dump_ctrl_res(ctrl);
+
+	return (rc);
+}
+
+int pciehprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, 
+				func-&gt;bus, func-&gt;device, func-&gt;function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void pciehprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &amp;command);
+
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;bcommand);
+
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_pciehprm_init_pci(void)
+{
+	return 0;
+}
+
+int pciehprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_pciehprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff -puN /dev/null drivers/pci/hotplug/pciehprm_nonacpi.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehprm_nonacpi.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,56 @@
+/*
+ * PCIEHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#ifndef _PCIEHPRM_NONACPI_H_
+#define _PCIEHPRM_NONACPI_H_
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _PCIEHPRM_NONACPI_H_ */
diff -puN /dev/null drivers/pci/hotplug/pciehp_sysfs.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/pciehp_sysfs.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,143 @@
+/*
+ * PCI Express Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/pci.h&gt;
+#include "pciehp.h"
+
+
+/* A few routines that create sysfs entries for the hot plug controller */
+
+static int show_ctrl (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	out += sprintf(buf, "Free resources: memory\n");
+	index = 11;
+	res = ctrl-&gt;mem_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+	out += sprintf(out, "Free resources: prefetchable memory\n");
+	index = 11;
+	res = ctrl-&gt;p_mem_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+	out += sprintf(out, "Free resources: IO\n");
+	index = 11;
+	res = ctrl-&gt;io_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+	out += sprintf(out, "Free resources: bus numbers\n");
+	index = 11;
+	res = ctrl-&gt;bus_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
+
+static int show_dev (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+	struct pci_func *new_slot;
+	struct slot *slot;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	slot=ctrl-&gt;slot;
+
+	while (slot) {
+		new_slot = pciehp_slot_find(slot-&gt;bus, slot-&gt;device, 0);
+		if (!new_slot)
+			break;
+		out += sprintf(out, "assigned resources: memory\n");
+		index = 11;
+		res = new_slot-&gt;mem_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		out += sprintf(out, "assigned resources: prefetchable memory\n");
+		index = 11;
+		res = new_slot-&gt;p_mem_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		out += sprintf(out, "assigned resources: IO\n");
+		index = 11;
+		res = new_slot-&gt;io_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		out += sprintf(out, "assigned resources: bus numbers\n");
+		index = 11;
+		res = new_slot-&gt;bus_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		slot=slot-&gt;next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL);
+
+void pciehp_create_ctrl_files (struct controller *ctrl)
+{
+	device_create_file (&amp;ctrl-&gt;pci_dev-&gt;dev, &amp;dev_attr_ctrl);
+	device_create_file (&amp;ctrl-&gt;pci_dev-&gt;dev, &amp;dev_attr_dev);
+}
diff -puN drivers/pci/hotplug/pci_hotplug_core.c~bk-pci drivers/pci/hotplug/pci_hotplug_core.c
--- 25/drivers/pci/hotplug/pci_hotplug_core.c~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/hotplug/pci_hotplug_core.c	2004-02-19 23:22:44.000000000 -0800
@@ -129,6 +129,7 @@ static char *pci_bus_speed_strings[] = {
 	"66 MHz PCIX 533",	/* 0x11 */
 	"100 MHz PCIX 533",	/* 0x12 */
 	"133 MHz PCIX 533",	/* 0x13 */
+	"25 GBps PCI-E",	/* 0x14 */
 };
 
 #ifdef CONFIG_HOTPLUG_PCI_CPCI
diff -puN drivers/pci/hotplug/pci_hotplug.h~bk-pci drivers/pci/hotplug/pci_hotplug.h
--- 25/drivers/pci/hotplug/pci_hotplug.h~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/hotplug/pci_hotplug.h	2004-02-19 23:22:44.000000000 -0800
@@ -36,6 +36,9 @@ enum pci_bus_speed {
 	PCI_SPEED_66MHz_PCIX		= 0x02,
 	PCI_SPEED_100MHz_PCIX		= 0x03,
 	PCI_SPEED_133MHz_PCIX		= 0x04,
+	PCI_SPEED_66MHz_PCIX_ECC	= 0x05,
+	PCI_SPEED_100MHz_PCIX_ECC	= 0x06,
+	PCI_SPEED_133MHz_PCIX_ECC	= 0x07,
 	PCI_SPEED_66MHz_PCIX_266	= 0x09,
 	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
 	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
@@ -45,6 +48,24 @@ enum pci_bus_speed {
 	PCI_SPEED_UNKNOWN		= 0xff,
 };
 
+/* These values come from the PCI Express Spec */
+enum pcie_link_width {
+	PCIE_LNK_WIDTH_RESRV	= 0x00,
+	PCIE_LNK_X1		= 0x01,
+	PCIE_LNK_X2		= 0x02,
+	PCIE_LNK_X4		= 0x04,
+	PCIE_LNK_X8		= 0x08,
+	PCIE_LNK_X12		= 0x0C,
+	PCIE_LNK_X16		= 0x10,
+	PCIE_LNK_X32		= 0x20,
+	PCIE_LNK_WIDTH_UNKNOWN  = 0xFF,
+};
+
+enum pcie_link_speed {
+	PCIE_2PT5GB		= 0x14,
+	PCIE_LNK_SPEED_UNKNOWN	= 0xFF,
+};
+
 struct hotplug_slot;
 struct hotplug_slot_attribute {
 	struct attribute attr;
diff -puN /dev/null drivers/pci/hotplug/rpadlpar_core.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/rpadlpar_core.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,343 @@
+/*
+ * Interface for Dynamic Logical Partitioning of I/O Slots on
+ * RPA-compliant PPC64 platform.
+ *
+ * John Rose &lt;johnrose@austin.ibm.com&gt;
+ * Linda Xie &lt;lxie@us.ibm.com&gt;
+ *
+ * October 2003
+ *
+ * Copyright (C) 2003 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include &lt;linux/init.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;asm/pci-bridge.h&gt;
+#include &lt;asm/semaphore.h&gt;
+#include "../pci.h"
+#include "rpaphp.h"
+#include "rpadlpar.h"
+
+static DECLARE_MUTEX(rpadlpar_sem);
+
+static inline int is_hotplug_capable(struct device_node *dn)
+{
+	unsigned char *ptr = get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL);
+
+	return (int) (ptr != NULL);
+}
+
+static char *get_node_drc_name(struct device_node *dn)
+{
+	char *ptr = NULL;
+	int *drc_names;
+
+	drc_names = (int *) get_property(dn, "ibm,drc-names", NULL);
+	if (drc_names)
+		ptr = (char *) &amp;drc_names[1];
+
+	return ptr;
+}
+
+static struct device_node *find_php_slot_node(char *drc_name)
+{
+	struct device_node *np = NULL;
+	char *name;
+
+	while ((np = of_find_node_by_type(np, "pci")))
+		if (is_hotplug_capable(np)) {
+			name = get_node_drc_name(np);
+			if (name &amp;&amp; (!strcmp(drc_name, name)))
+				break;
+		}
+
+	return np;
+}
+
+static inline struct hotplug_slot *find_php_slot(char *drc_name)
+{
+	struct kobject *k;
+
+	k = kset_find_obj(&amp;pci_hotplug_slots_subsys.kset, drc_name);
+	if (!k)
+		return NULL;
+
+	return to_hotplug_slot(k);
+}
+
+static struct slot *find_slot(char *drc_name)
+{
+	struct hotplug_slot *php_slot = find_php_slot(drc_name);
+	
+	if (!php_slot)
+		return NULL;
+
+	return (struct slot *) php_slot-&gt;private;
+}
+
+static void rpadlpar_claim_one_bus(struct pci_bus *b)
+{
+	struct list_head *ld;
+	struct pci_bus *child_bus;
+
+	for (ld = b-&gt;devices.next; ld != &amp;b-&gt;devices; ld = ld-&gt;next) {
+		struct pci_dev *dev = pci_dev_b(ld);
+		int i;
+
+		for (i = 0; i &lt; PCI_NUM_RESOURCES; i++) {
+			struct resource *r = &amp;dev-&gt;resource[i];
+
+			if (r-&gt;parent || !r-&gt;start || !r-&gt;flags)
+				continue;
+			rpaphp_claim_resource(dev, i);
+		}
+	}
+
+	list_for_each_entry(child_bus, &amp;b-&gt;children, node)
+		rpadlpar_claim_one_bus(child_bus);
+}
+
+static int pci_add_secondary_bus(struct device_node *dn,
+		struct pci_dev *bridge_dev)
+{
+	struct pci_controller *hose = dn-&gt;phb;
+	struct pci_bus *child;
+	u8 sec_busno;
+
+	/* Get busno of downstream bus */
+	pci_read_config_byte(bridge_dev, PCI_SECONDARY_BUS, &amp;sec_busno);
+
+	/* Allocate and add to children of bridge_dev-&gt;bus */
+	child = pci_add_new_bus(bridge_dev-&gt;bus, bridge_dev, sec_busno);
+	if (!child) {
+		printk(KERN_ERR "%s: could not add secondary bus\n", __FUNCTION__);
+		return 1;
+	}
+
+	sprintf(child-&gt;name, "PCI Bus #%02x", child-&gt;number);
+
+	/* Fixup subordinate bridge bases and resources */
+	pcibios_fixup_bus(child);
+
+	/* Claim new bus resources */
+	rpadlpar_claim_one_bus(bridge_dev-&gt;bus);
+
+	if (hose-&gt;last_busno &lt; child-&gt;number)
+	    	hose-&gt;last_busno = child-&gt;number;
+
+	dn-&gt;bussubno = child-&gt;number;
+
+	/* ioremap() for child bus */
+	if (remap_bus_range(child)) {
+		printk(KERN_ERR "%s: could not ioremap() child bus\n",
+				__FUNCTION__);
+		return 1;
+	}
+
+	return 0;
+}
+
+static struct pci_dev *dlpar_pci_add_bus(struct device_node *dn)
+{
+	struct pci_controller *hose = dn-&gt;phb;
+	struct pci_dev *dev = NULL;
+
+	/* Scan phb bus for EADS device, adding new one to bus-&gt;devices */
+	if (!pci_scan_single_device(hose-&gt;bus, dn-&gt;devfn)) {
+		printk(KERN_ERR "%s: found no device on bus\n", __FUNCTION__);
+		return NULL;
+	}
+
+	/* Add new devices to global lists.  Register in proc, sysfs. */
+	pci_bus_add_devices(hose-&gt;bus);
+
+	/* Confirm new bridge dev was created */
+	dev = rpaphp_find_pci_dev(dn);
+	if (!dev) {
+		printk(KERN_ERR "%s: failed to add pci device\n", __FUNCTION__);
+		return NULL;
+	}
+
+	if (dev-&gt;hdr_type != PCI_HEADER_TYPE_BRIDGE)  {
+		printk(KERN_ERR "%s: unexpected header type %d\n",
+				__FUNCTION__, dev-&gt;hdr_type);
+		return NULL;
+	}
+
+	if (pci_add_secondary_bus(dn, dev))
+		return NULL;
+
+	return dev;
+}
+
+static int dlpar_pci_remove_bus(struct pci_dev *bridge_dev)
+{
+	struct pci_bus *secondary_bus;
+
+	if (!bridge_dev) {
+		printk(KERN_ERR "%s: unexpected null device\n",
+				__FUNCTION__);
+		return 1;
+	}
+
+	secondary_bus = bridge_dev-&gt;subordinate;
+
+	if (unmap_bus_range(secondary_bus)) {
+		printk(KERN_ERR "%s: failed to unmap bus range\n",
+				__FUNCTION__);
+		return 1;
+	}
+
+	pci_remove_bus_device(bridge_dev);
+
+	return 0;
+}
+
+/**
+ * dlpar_add_slot - DLPAR add an I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Make the hotplug module and the kernel aware
+ * of a newly added I/O Slot.
+ * Return Codes -
+ * 0			Success
+ * -ENODEV		Not a valid drc_name
+ * -EINVAL		Slot already added
+ * -ERESTARTSYS		Signalled before obtaining lock
+ * -EIO			Internal PCI Error
+ */
+int dlpar_add_slot(char *drc_name)
+{
+	struct device_node *dn = find_php_slot_node(drc_name);
+	struct pci_dev *dev;
+	int rc = 0;
+
+	if (down_interruptible(&amp;rpadlpar_sem))
+		return -ERESTARTSYS;
+
+	if (!dn) {
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	/* Check for existing hotplug slot */
+	if (find_slot(drc_name)) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	/* Add pci bus */
+	dev = dlpar_pci_add_bus(dn);
+	if (!dev) {
+		printk(KERN_ERR "%s: unable to add bus %s\n", __FUNCTION__,
+				drc_name);
+		rc = -EIO;
+		goto exit;
+	}
+
+	/* Add hotplug slot for new bus */
+	if (rpaphp_add_slot(drc_name)) {
+		printk(KERN_ERR "%s: unable to add hotplug slot %s\n",
+				__FUNCTION__, drc_name);
+		rc = -EIO;
+	}
+exit:
+	up(&amp;rpadlpar_sem);
+	return rc;
+}
+
+/**
+ * dlpar_remove_slot - DLPAR remove an I/O Slot
+ * @drc_name: drc-name of newly added slot
+ *
+ * Remove the kernel and hotplug representations
+ * of an I/O Slot.
+ * Return Codes:
+ * 0			Success
+ * -ENODEV		Not a valid drc_name
+ * -EINVAL		Slot already removed
+ * -ERESTARTSYS		Signalled before obtaining lock
+ * -EIO			Internal PCI Error
+ */
+int dlpar_remove_slot(char *drc_name)
+{
+	struct device_node *dn = find_php_slot_node(drc_name);
+	struct slot *slot;
+	struct pci_dev *bridge_dev;
+	int rc = 0;
+
+	if (down_interruptible(&amp;rpadlpar_sem))
+		return -ERESTARTSYS;
+
+	if (!dn) {
+		rc = -ENODEV;
+		goto exit;
+	}
+
+	slot = find_slot(drc_name);
+	if (!slot) {
+		rc = -EINVAL;
+		goto exit;
+	}
+
+	bridge_dev = slot-&gt;bridge;
+	if (!bridge_dev) {
+		printk(KERN_ERR "%s: unexpected null bridge device\n",
+				__FUNCTION__);
+		rc = -EIO;
+		goto exit;
+	}
+
+	/* Remove hotplug slot */
+	if (rpaphp_remove_slot(slot)) {
+		printk(KERN_ERR "%s: unable to remove hotplug slot %s\n",
+				__FUNCTION__, drc_name);
+		rc = -EIO;
+		goto exit;
+	}
+
+	/* Remove pci bus */
+	if (dlpar_pci_remove_bus(bridge_dev)) {
+		printk(KERN_ERR "%s: unable to remove pci bus %s\n",
+				__FUNCTION__, drc_name);
+		rc = -EIO;
+	}
+exit:
+	up(&amp;rpadlpar_sem);
+	return rc;
+}
+
+static inline int is_dlpar_capable(void)
+{
+	int rc = rtas_token("ibm,configure-connector");
+
+	return (int) (rc != RTAS_UNKNOWN_SERVICE);
+}
+
+int __init rpadlpar_io_init(void)
+{
+	int rc = 0;
+
+	if (!is_dlpar_capable()) {
+		printk(KERN_WARNING "%s: partition not DLPAR capable\n",
+				__FUNCTION__);
+		return -EPERM;
+	}
+
+	rc = dlpar_sysfs_init();
+	return rc;
+}
+
+void rpadlpar_io_exit(void)
+{
+	dlpar_sysfs_exit();
+	return;
+}
+
+module_init(rpadlpar_io_init);
+module_exit(rpadlpar_io_exit);
+MODULE_LICENSE("GPL");
diff -puN /dev/null drivers/pci/hotplug/rpadlpar.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/rpadlpar.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,24 @@
+/*
+ * Interface for Dynamic Logical Partitioning of I/O Slots on
+ * RPA-compliant PPC64 platform.
+ *
+ * John Rose &lt;johnrose@austin.ibm.com&gt;
+ * October 2003
+ *
+ * Copyright (C) 2003 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#ifndef _RPADLPAR_IO_H_
+#define _RPADLPAR_IO_H_
+
+extern int dlpar_sysfs_init(void);
+extern void dlpar_sysfs_exit(void);
+
+extern int dlpar_add_slot(char *drc_name);
+extern int dlpar_remove_slot(char *drc_name);
+
+#endif
diff -puN /dev/null drivers/pci/hotplug/rpadlpar_sysfs.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/rpadlpar_sysfs.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,151 @@
+/*
+ * Interface for Dynamic Logical Partitioning of I/O Slots on
+ * RPA-compliant PPC64 platform.
+ *
+ * John Rose &lt;johnrose@austin.ibm.com&gt;
+ * October 2003
+ *
+ * Copyright (C) 2003 IBM.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include &lt;linux/kobject.h&gt;
+#include &lt;linux/string.h&gt;
+#include "pci_hotplug.h"
+#include "rpadlpar.h"
+
+#define DLPAR_KOBJ_NAME       "control"
+#define ADD_SLOT_ATTR_NAME    "add_slot"
+#define REMOVE_SLOT_ATTR_NAME "remove_slot"
+
+#define MAX_DRC_NAME_LEN 64
+
+/* Store return code of dlpar operation in attribute struct */
+struct dlpar_io_attr {
+	int rc;
+	struct attribute attr;
+	ssize_t (*store)(struct dlpar_io_attr *dlpar_attr, const char *buf,
+		size_t nbytes);
+};
+
+/* Common show callback for all attrs, display the return code
+ * of the dlpar op */
+static ssize_t
+dlpar_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
+{
+	struct dlpar_io_attr *dlpar_attr = container_of(attr,
+						struct dlpar_io_attr, attr);
+	return sprintf(buf, "%d\n", dlpar_attr-&gt;rc);
+}
+
+static ssize_t
+dlpar_attr_store(struct kobject * kobj, struct attribute * attr,
+		 const char *buf, size_t nbytes)
+{
+	struct dlpar_io_attr *dlpar_attr = container_of(attr,
+						struct dlpar_io_attr, attr);
+	return dlpar_attr-&gt;store ?
+		dlpar_attr-&gt;store(dlpar_attr, buf, nbytes) : 0;
+}
+
+static struct sysfs_ops dlpar_attr_sysfs_ops = {
+	.show = dlpar_attr_show,
+	.store = dlpar_attr_store,
+};
+
+static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr,
+				const char *buf, size_t nbytes)
+{
+	char drc_name[MAX_DRC_NAME_LEN];
+	char *end;
+
+	if (nbytes &gt; MAX_DRC_NAME_LEN)
+		return 0;
+
+	memcpy(drc_name, buf, nbytes);
+
+	end = strchr(drc_name, '\n');
+	if (!end)
+		end = &amp;drc_name[nbytes];
+	*end = '\0';
+
+	dlpar_attr-&gt;rc = dlpar_add_slot(drc_name);
+
+	return nbytes;
+}
+
+static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr,
+		 		const char *buf, size_t nbytes)
+{
+	char drc_name[MAX_DRC_NAME_LEN];
+	char *end;
+
+	if (nbytes &gt; MAX_DRC_NAME_LEN)
+		return 0;
+
+	memcpy(drc_name, buf, nbytes);
+
+	end = strchr(drc_name, '\n');
+	if (!end)
+		end = &amp;drc_name[nbytes];
+	*end = '\0';
+
+	dlpar_attr-&gt;rc = dlpar_remove_slot(drc_name);
+
+	return nbytes;
+}
+
+static struct dlpar_io_attr add_slot_attr = {
+	.rc = 0,
+	.attr = { .name = ADD_SLOT_ATTR_NAME, .mode = 0644, },
+	.store = add_slot_store,
+};
+
+static struct dlpar_io_attr remove_slot_attr = {
+	.rc = 0,
+	.attr = { .name = REMOVE_SLOT_ATTR_NAME, .mode = 0644},
+	.store = remove_slot_store,
+};
+
+static struct attribute *default_attrs[] = {
+	&amp;add_slot_attr.attr,
+	&amp;remove_slot_attr.attr,
+	NULL,
+};
+
+static void dlpar_io_release(struct kobject *kobj)
+{
+	/* noop */
+	return;
+}
+
+struct kobj_type ktype_dlpar_io = {
+	.release = dlpar_io_release,
+	.sysfs_ops = &amp;dlpar_attr_sysfs_ops,
+	.default_attrs = default_attrs,
+};
+
+struct kset dlpar_io_kset = {
+	.subsys = &amp;pci_hotplug_slots_subsys,
+	.kobj = {.name = DLPAR_KOBJ_NAME, .ktype=&amp;ktype_dlpar_io,},
+	.ktype = &amp;ktype_dlpar_io,
+};
+
+int dlpar_sysfs_init(void)
+{
+	if (kset_register(&amp;dlpar_io_kset)) {
+		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
+				dlpar_io_kset.kobj.name);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void dlpar_sysfs_exit(void)
+{
+	kset_unregister(&amp;dlpar_io_kset);
+}
diff -puN /dev/null drivers/pci/hotplug/rpaphp_core.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/rpaphp_core.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,948 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie &lt;lxie@us.ibm.com&gt;
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;lxie@us.ibm.com&gt;
+ *
+ */
+#include &lt;linux/config.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/moduleparam.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/smp.h&gt;
+#include &lt;linux/smp_lock.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;asm/rtas.h&gt;		/* rtas_call */
+#include &lt;asm/pci-bridge.h&gt;	/* for pci_controller */
+#include "../pci.h"		/* for pci_add_new_bus*/
+				/* and pci_do_scan_bus*/
+#include "rpaphp.h"
+#include "pci_hotplug.h"
+
+
+static int debug = 1;
+static struct semaphore rpaphp_sem;
+static LIST_HEAD (rpaphp_slot_head);
+static int num_slots;
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Linda Xie &lt;lxie@us.ibm.com&gt;"
+#define DRIVER_DESC	"RPA HOT Plug PCI Controller Driver"
+
+#define MAX_LOC_CODE 128
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, int, 0644);
+
+static int enable_slot(struct hotplug_slot *slot);
+static int disable_slot(struct hotplug_slot *slot);
+static int set_attention_status(struct hotplug_slot *slot, u8 value);
+static int get_power_status(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+	.owner			= THIS_MODULE,
+	.enable_slot		= enable_slot,
+	.disable_slot		= disable_slot,
+	.set_attention_status	= set_attention_status,
+	.get_power_status	= get_power_status,
+	.get_attention_status	= get_attention_status,
+	.get_adapter_status	= get_adapter_status,
+	.get_max_bus_speed	= get_max_bus_speed,
+	.get_cur_bus_speed	= get_cur_bus_speed,
+};
+
+static int rpaphp_get_sensor_state(int index, int *state)
+{
+	int rc;
+
+	rc = rtas_get_sensor(DR_ENTITY_SENSE, index, state);
+
+	if (rc) {
+		if (rc ==  NEED_POWER || rc == PWR_ONLY) {
+			dbg("%s: slot must be power up to get sensor-state\n",
+				__FUNCTION__);
+		} else if (rc == ERR_SENSE_USE)
+			info("%s: slot is unusable\n", __FUNCTION__);
+		   else err("%s failed to get sensor state\n", __FUNCTION__);
+	}
+	return rc;
+}
+
+static struct pci_dev *rpaphp_find_bridge_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot-&gt;dn);
+}
+
+static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot)
+{
+	return rpaphp_find_pci_dev(slot-&gt;dn-&gt;child);
+}
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check(struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL\n", function);
+		return -1;
+	}
+
+	if (!slot-&gt;hotplug_slot) {
+		dbg("%s - slot-&gt;hotplug_slot == NULL!\n", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot, const char *function)
+{
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot-&gt;private;
+	if (slot_paranoia_check(slot, function))
+		return NULL;
+	return slot;
+}
+
+static inline int rpaphp_set_attention_status(struct slot *slot, u8 status)
+{
+	int	rc;
+
+	/* status: LED_OFF or LED_ON */
+	rc = rtas_set_indicator(DR_INDICATOR, slot-&gt;index, status);
+	if (rc)
+		err("slot(%s) set attention-status(%d) failed! rc=0x%x\n",
+			slot-&gt;name, status, rc);
+	
+	return rc;
+}
+
+static int rpaphp_get_power_status(struct slot *slot, u8 *value)
+{
+	int	rc;
+
+	rc = rtas_get_power_level(slot-&gt;power_domain, (int *)value);
+	if (rc)
+		err("failed to get power-level for slot(%s), rc=0x%x\n",
+			slot-&gt;name, rc);
+
+	return rc;
+}
+
+static int rpaphp_get_attention_status(struct slot *slot)
+{
+
+	return slot-&gt;hotplug_slot-&gt;info-&gt;attention_status;
+}
+
+/**
+ * set_attention_status - set attention LED
+ * echo 0 &gt; attention -- set LED OFF
+ * echo 1 &gt; attention -- set LED ON
+ * echo 2 &gt; attention -- set LED ID(identify, light is blinking)
+ *
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value)
+{
+	int retval = 0;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&amp;rpaphp_sem);
+	switch (value) {
+		case 0:
+			retval = rpaphp_set_attention_status(slot, LED_OFF);
+			hotplug_slot-&gt;info-&gt;attention_status = 0;
+			break;
+
+		case 1:
+		default:
+			retval = rpaphp_set_attention_status(slot, LED_ON);
+			hotplug_slot-&gt;info-&gt;attention_status = 1;
+			break;
+
+		case 2:
+			retval = rpaphp_set_attention_status(slot, LED_ID);
+			hotplug_slot-&gt;info-&gt;attention_status = 2;
+			break;
+
+	}
+	up(&amp;rpaphp_sem);
+	
+	return retval;
+}
+
+/**
+ * get_power_status - get power status of a slot
+ * @hotplug_slot: slot to get status
+ * @value: pointer to store status
+ *
+ *
+ */
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&amp;rpaphp_sem);
+	retval = rpaphp_get_power_status(slot, value);
+	up(&amp;rpaphp_sem);
+
+	return retval;
+}
+
+/**
+ * get_attention_status - get attention LED status
+ *
+ *
+ */
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	int retval = 0;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+
+	down(&amp;rpaphp_sem);
+	*value = rpaphp_get_attention_status(slot);
+	up(&amp;rpaphp_sem);
+
+	return retval;
+}
+
+/*
+ * get_adapter_status - get  the status of a slot
+ *
+ * 0-- slot is empty
+ * 1-- adapter is configured
+ * 2-- adapter is not configured
+ * 3-- not valid
+ */
+static int rpaphp_get_adapter_status(struct slot *slot, int is_init, u8 *value)
+{
+	int	state, rc;
+
+	*value 		  = NOT_VALID;
+
+	rc = rpaphp_get_sensor_state(slot-&gt;index, &amp;state);
+
+	if (rc)
+		return rc;
+
+	if (state == PRESENT) {
+		dbg("slot is occupied\n");
+
+		if (!is_init) /* at run-time slot-&gt;state can be changed by */
+			  /* config/unconfig adapter	 		   */
+			*value = slot-&gt;state;
+		else {
+		if (!slot-&gt;dn-&gt;child)
+			dbg("%s: %s is not valid OFDT node\n",
+				__FUNCTION__, slot-&gt;dn-&gt;full_name);
+		else
+			if (rpaphp_find_pci_dev(slot-&gt;dn-&gt;child))
+				*value = CONFIGURED;
+			else {
+				dbg("%s: can't find pdev of adapter in slot[%s]\n",
+					__FUNCTION__, slot-&gt;name);
+				*value = NOT_CONFIGURED;
+				}
+		}
+	} else
+		if (state == EMPTY) {
+		dbg("slot is empty\n");
+			*value = state;
+		}
+	
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+	int retval = 0;
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&amp;rpaphp_sem);
+
+	/*  have to go through this */
+	retval = rpaphp_get_adapter_status(slot, 0, value);
+
+	up(&amp;rpaphp_sem);
+
+	return retval;
+}
+
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	down(&amp;rpaphp_sem);
+
+	switch (slot-&gt;type) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+		case 6:
+			*value = PCI_SPEED_33MHz;	/* speed for case 1-6 */
+			break;
+		case 7:
+		case 8:
+			*value = PCI_SPEED_66MHz;
+			break;
+		case 11:
+		case 14:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 12:
+		case 15:
+			*value = PCI_SPEED_100MHz_PCIX;
+			break;
+		case 13:
+		case 16:
+			*value = PCI_SPEED_133MHz_PCIX;
+			break;
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			break;
+
+	}
+
+	up(&amp;rpaphp_sem);
+
+	return 0;
+}
+
+
+/* return dummy value because not sure if PRA provides any method... */
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+/*
+ * rpaphp_validate_slot - make sure the name of the slot matches
+ * 				the location code , if the slots is not
+ *				empty.
+ */
+static int rpaphp_validate_slot(const char *slot_name, const int slot_index)
+{
+	struct device_node	*dn;
+
+	for(dn = find_all_nodes(); dn; dn = dn-&gt;next) {
+
+		int 		*index;
+		unsigned char	*loc_code;
+
+		index  = (int *)get_property(dn, "ibm,my-drc-index", NULL);
+
+		if (index &amp;&amp; *index == slot_index) {
+			char *slash, *tmp_str;
+
+			loc_code = get_property(dn, "ibm,loc-code", NULL);
+			if (!loc_code) { 
+				return -1;
+			}
+
+			tmp_str = kmalloc(MAX_LOC_CODE, GFP_KERNEL); 
+			if (!tmp_str) {
+				err("%s: out of memory\n", __FUNCTION__);
+				return -1;
+			}
+				
+			strcpy(tmp_str, loc_code);
+			slash = strrchr(tmp_str, '/');
+			if (slash) 
+				*slash = '\0';
+			
+			if (strcmp(slot_name, tmp_str)) {
+				kfree(tmp_str);
+				return -1;
+			}
+
+			kfree(tmp_str);
+			break;
+		}
+	}
+	
+	return 0;
+}
+
+/* Must be called before pci_bus_add_devices */
+static void rpaphp_fixup_new_devices(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &amp;bus-&gt;devices, bus_list) {
+	/*
+	 * Skip already-present devices (which are on the
+	 * global device list.)
+	 */
+		if (list_empty(&amp;dev-&gt;global_list)) {
+			int i;
+			pcibios_fixup_device_resources(dev, bus);
+			pci_read_irq_line(dev);
+			for (i = 0; i &lt; PCI_NUM_RESOURCES; i++) {
+				struct resource *r = &amp;dev-&gt;resource[i];
+				if (r-&gt;parent || !r-&gt;start || !r-&gt;flags)
+					continue;
+				rpaphp_claim_resource(dev, i);
+			}
+		}
+	}
+}
+
+static struct pci_dev *rpaphp_config_adapter(struct slot *slot)
+{
+	struct pci_bus 		*pci_bus;
+	struct device_node	*dn;
+	int 			num;
+	struct pci_dev		*dev = NULL;
+
+	if (slot-&gt;bridge) {
+
+		pci_bus = slot-&gt;bridge-&gt;subordinate;
+
+		if (!pci_bus) {
+			err("%s: can't find bus structure\n", __FUNCTION__);
+			goto exit;
+		}
+
+		for (dn = slot-&gt;dn-&gt;child; dn; dn = dn-&gt;sibling) {
+			dbg("child dn's devfn=[%x]\n", dn-&gt;devfn);
+				num = pci_scan_slot(pci_bus,
+				PCI_DEVFN(PCI_SLOT(dn-&gt;devfn),  0));
+
+				dbg("pci_scan_slot return num=%d\n", num);
+
+			if (num) {
+				rpaphp_fixup_new_devices(pci_bus);
+				pci_bus_add_devices(pci_bus);
+			}
+		}
+
+		dev = rpaphp_find_pci_dev(slot-&gt;dn-&gt;child);
+	} else {
+		/* slot is not enabled */
+		err("slot doesn't have pci_dev structure\n");
+		dev = NULL;
+		goto exit;
+	}
+
+exit:
+	dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev? "found":"not found");
+
+	return dev;
+}
+
+static int rpaphp_unconfig_adapter(struct slot *slot)
+{
+	if (!slot-&gt;dev) {
+		info("%s: no card in slot[%s]\n",
+			__FUNCTION__, slot-&gt;name);
+
+		return -EINVAL;
+	}
+
+	/* remove the device from the pci core */
+	pci_remove_bus_device(slot-&gt;dev);
+
+	pci_dev_put(slot-&gt;dev);
+	slot-&gt;state = NOT_CONFIGURED;
+
+	dbg("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__, slot-&gt;name);
+
+	return 0;
+}
+
+/* free up the memory user be a slot */
+
+static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return;
+
+	kfree(slot-&gt;hotplug_slot-&gt;info);
+	kfree(slot-&gt;hotplug_slot-&gt;name);
+	kfree(slot-&gt;hotplug_slot);
+	pci_dev_put(slot-&gt;bridge);
+	pci_dev_put(slot-&gt;dev);
+	kfree(slot);
+}
+
+int rpaphp_remove_slot(struct slot *slot)
+{
+	int retval = 0;
+
+  	sysfs_remove_link(slot-&gt;hotplug_slot-&gt;kobj.parent,
+			slot-&gt;bridge-&gt;slot_name);
+
+	list_del(&amp;slot-&gt;rpaphp_slot_list);
+	retval = pci_hp_deregister(slot-&gt;hotplug_slot);
+	if (retval)
+		err("Problem unregistering a slot %s\n", slot-&gt;name);
+	num_slots--;
+
+	return retval;
+}
+
+static int is_php_dn(struct device_node *dn, int **indexes,  int **names, int **types, int **power_domains)
+{
+	*indexes = (int *)get_property(dn, "ibm,drc-indexes", NULL);
+	if (!*indexes)
+		return(0);
+
+	/* &amp;names[1] contains NULL terminated slot names */
+	*names = (int *)get_property(dn, "ibm,drc-names", NULL);
+	if (!*names)
+		return(0);
+
+	/* &amp;types[1] contains NULL terminated slot types */
+	*types = (int *)get_property(dn, "ibm,drc-types", NULL);
+	if (!*types)
+		return(0);
+
+	/* power_domains[1...n] are the slot power domains */
+	*power_domains = (int *)get_property(dn,
+		"ibm,drc-power-domains", NULL);
+	if (!*power_domains)
+		return(0);
+
+	if (!get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL))
+		return(0);
+
+	return(1);
+}
+
+static struct slot *alloc_slot_struct(void)
+{
+	struct slot *slot;
+
+	slot = kmalloc(sizeof(struct slot), GFP_KERNEL);
+	if (!slot)
+		return (NULL);
+	memset(slot, 0, sizeof(struct slot));
+	slot-&gt;hotplug_slot = kmalloc(sizeof(struct hotplug_slot),
+		GFP_KERNEL);
+	if (!slot-&gt;hotplug_slot) {
+		kfree(slot);
+		return (NULL);
+	}
+	memset(slot-&gt;hotplug_slot, 0, sizeof(struct hotplug_slot));
+	slot-&gt;hotplug_slot-&gt;info = kmalloc(sizeof(struct hotplug_slot_info),
+		GFP_KERNEL);
+	if (!slot-&gt;hotplug_slot-&gt;info) {
+		kfree(slot-&gt;hotplug_slot);
+		kfree(slot);
+		return (NULL);
+	}
+	memset(slot-&gt;hotplug_slot-&gt;info, 0, sizeof(struct hotplug_slot_info));
+	slot-&gt;hotplug_slot-&gt;name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+	if (!slot-&gt;hotplug_slot-&gt;name) {
+		kfree(slot-&gt;hotplug_slot-&gt;info);
+		kfree(slot-&gt;hotplug_slot);
+		kfree(slot);
+		return (NULL);
+	}
+	return (slot);
+}
+
+static int setup_hotplug_slot_info(struct slot *slot)
+{
+	rpaphp_get_power_status(slot,
+		&amp;slot-&gt;hotplug_slot-&gt;info-&gt;power_status);
+
+	rpaphp_get_adapter_status(slot, 1,
+		&amp;slot-&gt;hotplug_slot-&gt;info-&gt;adapter_status);
+
+	if (slot-&gt;hotplug_slot-&gt;info-&gt;adapter_status == NOT_VALID) {
+		dbg("%s: NOT_VALID: skip dn-&gt;full_name=%s\n",
+			__FUNCTION__, slot-&gt;dn-&gt;full_name);
+		    kfree(slot-&gt;hotplug_slot-&gt;info);
+		    kfree(slot-&gt;hotplug_slot-&gt;name);
+		    kfree(slot-&gt;hotplug_slot);
+		    kfree(slot);
+		return (-1);
+	}
+	return (0);
+}
+
+static int register_slot(struct slot *slot)
+{
+	int retval;
+
+	retval = pci_hp_register(slot-&gt;hotplug_slot);
+	if (retval) {
+		err("pci_hp_register failed with error %d\n", retval);
+		rpaphp_release_slot(slot-&gt;hotplug_slot);
+		return (retval);
+	}
+	/* create symlink between slot-&gt;name and it's bus_id */
+	dbg("%s: sysfs_create_link: %s --&gt; %s\n", __FUNCTION__,
+		slot-&gt;bridge-&gt;slot_name, slot-&gt;name);
+	retval = sysfs_create_link(slot-&gt;hotplug_slot-&gt;kobj.parent,
+			&amp;slot-&gt;hotplug_slot-&gt;kobj,
+			slot-&gt;bridge-&gt;slot_name);
+	if (retval) {
+		err("sysfs_create_link failed with error %d\n", retval);
+		rpaphp_release_slot(slot-&gt;hotplug_slot);
+		return (retval);
+	}
+	/* add slot to our internal list */
+	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
+		__FUNCTION__, slot-&gt;name);
+
+	list_add(&amp;slot-&gt;rpaphp_slot_list, &amp;rpaphp_slot_head);
+
+	info("Slot [%s] (bus_id=%s) registered\n",
+		slot-&gt;name, slot-&gt;bridge-&gt;slot_name);
+	return (0);
+}
+
+/*************************************
+ * Add  Hot Plug slot(s) to sysfs
+ *
+ ************************************/
+int rpaphp_add_slot(char *slot_name)
+{
+	struct slot		*slot;
+	int 			retval = 0;
+	int 			i;
+	struct device_node 	*dn;
+	int 			*indexes, *names, *types, *power_domains;
+	char 			*name, *type;
+
+	for (dn = find_all_nodes(); dn; dn = dn-&gt;next) {
+
+		if (dn-&gt;name != 0 &amp;&amp; strcmp(dn-&gt;name, "pci") == 0)	{
+			if (!is_php_dn(dn, &amp;indexes, &amp;names, &amp;types, &amp;power_domains))
+				continue;
+
+			dbg("%s : found device_node in OFDT full_name=%s, name=%s\n",
+				__FUNCTION__, dn-&gt;full_name, dn-&gt;name);
+
+			name = (char *)&amp;names[1];
+			type = (char *)&amp;types[1];
+
+			for (i = 0; i &lt; indexes[0];
+				i++,
+				name += (strlen(name) + 1),
+				type += (strlen(type) + 1)) {
+
+				dbg("%s: name[%s] index[%x]\n",
+					__FUNCTION__, name, indexes[i+1]);
+
+				if (slot_name &amp;&amp; strcmp(slot_name, name))
+					continue;
+
+				if (rpaphp_validate_slot(name, indexes[i + 1])) {
+					dbg("%s: slot(%s, 0x%x) is invalid.\n",
+						__FUNCTION__, name, indexes[i+ 1]);
+					continue;
+				}
+
+				slot = alloc_slot_struct();
+				if (!slot) {
+					retval = -ENOMEM;
+					goto exit;
+				}
+
+				slot-&gt;name = slot-&gt;hotplug_slot-&gt;name;
+				slot-&gt;index = indexes[i + 1];
+				strcpy(slot-&gt;name, name);
+				slot-&gt;type = simple_strtoul(type, NULL, 10);
+				if (slot-&gt;type &lt; 1  || slot-&gt;type &gt; 16)
+					slot-&gt;type = 0;
+
+				slot-&gt;power_domain = power_domains[i + 1];
+				slot-&gt;magic = SLOT_MAGIC;
+				slot-&gt;hotplug_slot-&gt;private = slot;
+				slot-&gt;hotplug_slot-&gt;ops = &amp;rpaphp_hotplug_slot_ops;
+				slot-&gt;hotplug_slot-&gt;release = &amp;rpaphp_release_slot;
+				slot-&gt;dn = dn;
+
+				/*
+			 	* Initilize the slot info structure with some known
+			 	* good values.
+			 	*/
+				if (setup_hotplug_slot_info(slot))
+					continue;
+
+				slot-&gt;bridge = rpaphp_find_bridge_pdev(slot);
+				if (!slot-&gt;bridge &amp;&amp; slot_name) { /* slot being added doesn't have pci_dev yet*/
+					dbg("%s: no pci_dev for bridge dn %s\n",
+							__FUNCTION__, slot_name);
+					kfree(slot-&gt;hotplug_slot-&gt;info);
+					kfree(slot-&gt;hotplug_slot-&gt;name);
+					kfree(slot-&gt;hotplug_slot);
+					kfree(slot);
+					continue;
+				}
+
+				/* find slot's pci_dev if it's not empty*/
+				if (slot-&gt;hotplug_slot-&gt;info-&gt;adapter_status == EMPTY) {
+					slot-&gt;state = EMPTY;  /* slot is empty */
+					slot-&gt;dev = NULL;
+				} else {  /* slot is occupied */
+					if(!(slot-&gt;dn-&gt;child)) { /* non-empty slot has to have child */
+						err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
+						__FUNCTION__, slot-&gt;name);
+						kfree(slot-&gt;hotplug_slot-&gt;info);
+						kfree(slot-&gt;hotplug_slot-&gt;name);
+						kfree(slot-&gt;hotplug_slot);
+						kfree(slot);
+						continue;
+
+					}
+
+					slot-&gt;dev = rpaphp_find_adapter_pdev(slot);
+					if(slot-&gt;dev) {
+						slot-&gt;state = CONFIGURED;
+						pci_dev_get(slot-&gt;dev);
+					} else {
+						/* DLPAR add as opposed to
+						 * boot time */
+						slot-&gt;state = NOT_CONFIGURED;
+						}
+				}
+				dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
+					__FUNCTION__, dn-&gt;full_name, slot-&gt;index, slot-&gt;name,
+					slot-&gt;power_domain, slot-&gt;type);
+
+				retval = register_slot(slot);
+				if (retval)
+					goto exit;
+
+				num_slots++;
+
+				if (slot_name)
+					goto exit;
+
+			}/* for indexes */
+		}/* "pci" */
+	}/* find_all_nodes */
+exit:
+	dbg("%s - Exit: num_slots=%d rc[%d]\n",
+		__FUNCTION__, num_slots, retval);
+	return retval;
+}
+
+/*
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static int init_slots (void)
+{
+	int 			retval = 0;
+
+	retval = rpaphp_add_slot(NULL);
+
+	return retval;
+}
+
+
+static int init_rpa (void)
+{
+	int 			retval = 0;
+
+	init_MUTEX(&amp;rpaphp_sem);
+
+	/* initialize internal data structure etc. */
+	retval = init_slots();
+	if (!num_slots)
+		retval = -ENODEV;
+
+	return retval;
+}
+
+static void cleanup_slots (void)
+{
+	struct list_head *tmp, *n;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 * memory will be freed in release_slot callback.
+	 */
+
+	list_for_each_safe (tmp, n, &amp;rpaphp_slot_head) {
+		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+		sysfs_remove_link(slot-&gt;hotplug_slot-&gt;kobj.parent,
+			slot-&gt;bridge-&gt;slot_name);
+		list_del(&amp;slot-&gt;rpaphp_slot_list);
+		pci_hp_deregister(slot-&gt;hotplug_slot);
+	}
+
+	return;
+}
+
+
+static int __init rpaphp_init(void)
+{
+	int retval = 0;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	rpaphp_debug = debug;
+
+	/* read all the PRA info from the system */
+	retval = init_rpa();
+
+	return retval;
+}
+
+
+static void __exit rpaphp_exit(void)
+{
+	cleanup_slots();
+}
+
+
+static int enable_slot(struct hotplug_slot *hotplug_slot)
+{
+	int retval = 0, state;
+
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	if (slot-&gt;state == CONFIGURED) {
+		dbg("%s: %s is already enabled\n",
+			__FUNCTION__, slot-&gt;name);
+		goto exit;
+	}
+
+	dbg("ENABLING SLOT %s\n", slot-&gt;name);
+
+	down(&amp;rpaphp_sem);
+
+	retval = rpaphp_get_sensor_state(slot-&gt;index, &amp;state);
+
+	if (retval)
+		goto exit;
+
+	dbg("%s: sensor state[%d]\n", __FUNCTION__, state);
+
+	/* if slot is not empty, enable the adapter */
+	if (state == PRESENT) {
+		dbg("%s : slot[%s] is occupid.\n", __FUNCTION__, slot-&gt;name);
+
+		
+		slot-&gt;dev = rpaphp_config_adapter(slot);
+		if (slot-&gt;dev != NULL) {
+			slot-&gt;state = CONFIGURED;
+
+			dbg("%s: adapter %s in slot[%s] has been configured\n",
+				__FUNCTION__, slot-&gt;dev-&gt;slot_name,
+				slot-&gt;name);
+		} else {
+			slot-&gt;state = NOT_CONFIGURED;
+
+			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
+				__FUNCTION__, slot-&gt;name);
+		}
+
+	} else if (state == EMPTY) {
+		dbg("%s : slot[%s] is empty\n", __FUNCTION__, slot-&gt;name);
+		slot-&gt;state = EMPTY;
+	} else {
+		err("%s: slot[%s] is in invalid state\n", __FUNCTION__, slot-&gt;name);
+		slot-&gt;state = NOT_VALID;
+		retval = -EINVAL;
+	}
+
+exit:
+	if (slot-&gt;state != NOT_VALID)
+		rpaphp_set_attention_status(slot, LED_ON);
+	else
+		rpaphp_set_attention_status(slot, LED_ID);
+
+	up(&amp;rpaphp_sem);
+
+	return retval;
+}
+
+static int disable_slot(struct hotplug_slot *hotplug_slot)
+{
+	int	retval;
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("DISABLING SLOT %s\n", slot-&gt;name);
+
+	down(&amp;rpaphp_sem);
+
+	rpaphp_set_attention_status(slot, LED_ID);
+
+	retval = rpaphp_unconfig_adapter(slot);
+
+	rpaphp_set_attention_status(slot, LED_OFF);
+
+	up(&amp;rpaphp_sem);
+
+	return retval;
+}
+
+module_init(rpaphp_init);
+module_exit(rpaphp_exit);
+
+EXPORT_SYMBOL_GPL(rpaphp_add_slot);
+EXPORT_SYMBOL_GPL(rpaphp_remove_slot);
diff -puN /dev/null drivers/pci/hotplug/rpaphp.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/rpaphp.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,101 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ *
+ * Copyright (C) 2003 Linda Xie &lt;lxie@us.ibm.com&gt;
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;lxie@us.ibm.com&gt;,
+ *
+ */
+
+#ifndef _PPC64PHP_H
+#define _PPC64PHP_H
+#include "pci_hotplug.h"
+
+#define DR_INDICATOR 9002
+#define DR_ENTITY_SENSE 9003
+
+#define POWER_ON	100
+#define POWER_OFF	0
+
+#define LED_OFF		0 
+#define LED_ON		1	/* continuous on */ 
+#define LED_ID		2	/* slow blinking */
+#define LED_ACTION	3	/* fast blinking */
+
+#define SLOT_NAME_SIZE 12
+
+/* Error status from rtas_get-sensor */
+#define NEED_POWER    -9000     /* slot must be power up and unisolated to get state */
+#define PWR_ONLY      -9001     /* slot must be powerd up to get state, leave isolated */
+#define ERR_SENSE_USE -9002     /* No DR operation will succeed, slot is unusable  */
+
+/* Sensor values from rtas_get-sensor */
+#define EMPTY	0       /* No card in slot */
+#define PRESENT	1       /* Card in slot */
+
+#define MY_NAME "rpaphp"
+
+#define dbg(format, arg...)					\
+	do {							\
+		if (rpaphp_debug)				\
+			printk(KERN_DEBUG "%s: " format,	\
+				MY_NAME , ## arg); 		\
+	} while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+#define SLOT_MAGIC	0x67267322
+
+/* slot states */
+
+#define	NOT_VALID	3
+#define	NOT_CONFIGURED	2
+#define	CONFIGURED	1
+#define	EMPTY		0
+
+/*
+ * struct slot - slot information for each *physical* slot
+ */
+struct slot {
+	u32	magic;
+	int     state;
+	u32     index;
+	u32     type;
+	u32     power_domain;
+	char    *name;
+	struct	device_node *dn;/* slot's device_node in OFDT		*/
+				/* dn has phb info			*/
+	struct	pci_dev	*bridge;/* slot's pci_dev in pci_devices	*/
+
+	struct	pci_dev	*dev;	/* pci_dev of device in this slot 	*/
+				/* it will be used for unconfig		*/ 
+				/* NULL if slot is empty		*/
+
+	struct  hotplug_slot    *hotplug_slot;
+	struct list_head	rpaphp_slot_list;
+};
+
+extern struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn);
+extern int rpaphp_add_slot(char *slot_name);
+extern int rpaphp_remove_slot(struct slot *slot);
+extern int rpaphp_claim_resource(struct pci_dev *dev, int resource);
+
+#endif /* _PPC64PHP_H */
diff -puN /dev/null drivers/pci/hotplug/rpaphp_pci.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/rpaphp_pci.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,75 @@
+/*
+ * PCI Hot Plug Controller Driver for RPA-compliant PPC64 platform.
+ * Copyright (C) 2003 Linda Xie &lt;lxie@us.ibm.com&gt;
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;lxie@us.ibm.com&gt;
+ *
+ */
+#include &lt;linux/pci.h&gt;
+#include &lt;asm/pci-bridge.h&gt;	/* for pci_controller */
+#include "rpaphp.h"
+
+
+struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn)
+{
+	struct pci_dev		*retval_dev = NULL, *dev = NULL;
+
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		if(!dev-&gt;bus)
+			continue;
+
+		if (dev-&gt;devfn != dn-&gt;devfn)
+			continue;
+
+		if (dn-&gt;phb-&gt;global_number == pci_domain_nr(dev-&gt;bus) &amp;&amp;
+		    dn-&gt;busno == dev-&gt;bus-&gt;number) {
+			retval_dev = dev;
+			break;
+		}
+	}
+
+	return retval_dev;
+
+}
+
+int rpaphp_claim_resource(struct pci_dev *dev, int resource)
+{
+	struct resource *res = &amp;dev-&gt;resource[resource];
+	struct resource *root = pci_find_parent_resource(dev, res);
+	char *dtype = resource &lt; PCI_BRIDGE_RESOURCES ? "device" : "bridge";
+	int err;
+
+	err = -EINVAL;
+	if (root != NULL) {
+		err = request_resource(root, res);
+	}
+
+	if (err) {
+		err("PCI: %s region %d of %s %s [%lx:%lx]\n",
+			root ? "Address space collision on" :
+			"No parent found for",
+			resource, dtype, pci_name(dev), res-&gt;start, res-&gt;end);
+	}
+
+	return err;
+}
+
+EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
+EXPORT_SYMBOL_GPL(rpaphp_claim_resource);
diff -puN /dev/null drivers/pci/hotplug/shpchp_core.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchp_core.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,704 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/miscdevice.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include "shpchp.h"
+#include "shpchprm.h"
+
+/* Global variables */
+int shpchp_debug;
+int shpchp_poll_mode;
+int shpchp_poll_time;
+struct controller *shpchp_ctrl_list;	/* = NULL */
+struct pci_func *shpchp_slot_list[256];
+
+#define DRIVER_VERSION	"0.4"
+#define DRIVER_AUTHOR	"Dan Zink &lt;dan.zink@compaq.com&gt;, Greg Kroah-Hartman &lt;greg@kroah.com&gt;, Dely Sy &lt;dely.l.sy@intel.com&gt;"
+#define DRIVER_DESC	"Standard Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(shpchp_debug, "i");
+MODULE_PARM(shpchp_poll_mode, "i");
+MODULE_PARM(shpchp_poll_time, "i");
+MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
+MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
+MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
+
+#define SHPC_MODULE_NAME "shpchp"
+
+static int shpc_start_thread (void);
+static int set_attention_status (struct hotplug_slot *slot, u8 value);
+static int enable_slot		(struct hotplug_slot *slot);
+static int disable_slot		(struct hotplug_slot *slot);
+static int hardware_test	(struct hotplug_slot *slot, u32 value);
+static int get_power_status	(struct hotplug_slot *slot, u8 *value);
+static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
+static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
+static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+
+static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
+	.owner =		THIS_MODULE,
+	.set_attention_status =	set_attention_status,
+	.enable_slot =		enable_slot,
+	.disable_slot =		disable_slot,
+	.hardware_test =	hardware_test,
+	.get_power_status =	get_power_status,
+	.get_attention_status =	get_attention_status,
+	.get_latch_status =		get_latch_status,
+	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
+};
+
+static int init_slots(struct controller *ctrl)
+{
+	struct slot *new_slot;
+	u8 number_of_slots;
+	u8 slot_device;
+	u32 slot_number, sun;
+	int result;
+
+	dbg("%s\n",__FUNCTION__);
+
+	number_of_slots = ctrl-&gt;num_slots;
+	slot_device = ctrl-&gt;slot_device_offset;
+	slot_number = ctrl-&gt;first_slot;
+
+	while (number_of_slots) {
+		new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL);
+		if (!new_slot)
+			return -ENOMEM;
+
+		memset(new_slot, 0, sizeof(struct slot));
+		new_slot-&gt;hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL);
+		if (!new_slot-&gt;hotplug_slot) {
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot-&gt;hotplug_slot, 0, sizeof (struct hotplug_slot));
+
+		new_slot-&gt;hotplug_slot-&gt;info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if (!new_slot-&gt;hotplug_slot-&gt;info) {
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+		memset(new_slot-&gt;hotplug_slot-&gt;info, 0, sizeof (struct hotplug_slot_info));
+		new_slot-&gt;hotplug_slot-&gt;name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		if (!new_slot-&gt;hotplug_slot-&gt;name) {
+			kfree (new_slot-&gt;hotplug_slot-&gt;info);
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+
+		new_slot-&gt;magic = SLOT_MAGIC;
+		new_slot-&gt;ctrl = ctrl;
+		new_slot-&gt;bus = ctrl-&gt;slot_bus;
+		new_slot-&gt;device = slot_device;
+		new_slot-&gt;hpc_ops = ctrl-&gt;hpc_ops;
+
+		if (shpchprm_get_physical_slot_number(ctrl, &amp;sun, new_slot-&gt;bus, new_slot-&gt;device)) {
+			kfree (new_slot-&gt;hotplug_slot-&gt;info);
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return -ENOMEM;
+		}
+
+		new_slot-&gt;number = sun;
+		new_slot-&gt;hp_slot = slot_device - ctrl-&gt;slot_device_offset;
+
+		/* register this slot with the hotplug pci core */
+		new_slot-&gt;hotplug_slot-&gt;private = new_slot;
+		make_slot_name (new_slot-&gt;hotplug_slot-&gt;name, SLOT_NAME_SIZE, new_slot);
+		new_slot-&gt;hotplug_slot-&gt;ops = &amp;shpchp_hotplug_slot_ops;
+
+		new_slot-&gt;hpc_ops-&gt;get_power_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;power_status));
+		new_slot-&gt;hpc_ops-&gt;get_attention_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;attention_status));
+		new_slot-&gt;hpc_ops-&gt;get_latch_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;latch_status));
+		new_slot-&gt;hpc_ops-&gt;get_adapter_status(new_slot, &amp;(new_slot-&gt;hotplug_slot-&gt;info-&gt;adapter_status));
+
+		dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x slot_device_offset=%x\n", new_slot-&gt;bus, 
+			new_slot-&gt;device, new_slot-&gt;hp_slot, new_slot-&gt;number, ctrl-&gt;slot_device_offset);
+		result = pci_hp_register (new_slot-&gt;hotplug_slot);
+		if (result) {
+			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot-&gt;hotplug_slot-&gt;info);
+			kfree (new_slot-&gt;hotplug_slot-&gt;name);
+			kfree (new_slot-&gt;hotplug_slot);
+			kfree (new_slot);
+			return result;
+		}
+
+		new_slot-&gt;next = ctrl-&gt;slot;
+		ctrl-&gt;slot = new_slot;
+
+		number_of_slots--;
+		slot_device++;
+		slot_number += ctrl-&gt;slot_num_inc;
+	}
+
+	return(0);
+}
+
+
+static int cleanup_slots (struct controller * ctrl)
+{
+	struct slot *old_slot, *next_slot;
+
+	old_slot = ctrl-&gt;slot;
+	ctrl-&gt;slot = NULL;
+
+	while (old_slot) {
+		next_slot = old_slot-&gt;next;
+		pci_hp_deregister (old_slot-&gt;hotplug_slot);
+		kfree(old_slot-&gt;hotplug_slot-&gt;info);
+		kfree(old_slot-&gt;hotplug_slot-&gt;name);
+		kfree(old_slot-&gt;hotplug_slot);
+		kfree(old_slot);
+		old_slot = next_slot;
+	}
+
+
+	return(0);
+}
+
+static int get_ctlr_slot_config(struct controller *ctrl)
+{
+	int num_ctlr_slots;
+	int first_device_num;
+	int physical_slot_num;
+	int updown;
+	int rc;
+	int flags;
+
+	rc = shpc_get_ctlr_slot_config(ctrl, &amp;num_ctlr_slots, &amp;first_device_num, &amp;physical_slot_num, &amp;updown, &amp;flags);
+	if (rc) {
+		err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl-&gt;bus, ctrl-&gt;device);
+		return (-1);
+	}
+
+	ctrl-&gt;num_slots = num_ctlr_slots;
+	ctrl-&gt;slot_device_offset = first_device_num;
+	ctrl-&gt;first_slot = physical_slot_num;
+	ctrl-&gt;slot_num_inc = updown;		/* either -1 or 1 */
+
+	dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n",
+		__FUNCTION__, num_ctlr_slots, first_device_num, physical_slot_num, updown, ctrl-&gt;bus, ctrl-&gt;device);
+
+	return (0);
+}
+
+
+/*
+ * set_attention_status - Turns the Amber LED for a slot on, off or blink
+ */
+static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	hotplug_slot-&gt;info-&gt;attention_status = status;
+	slot-&gt;hpc_ops-&gt;set_attention_status(slot, status);
+
+
+	return 0;
+}
+
+
+static int enable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	return shpchp_enable_slot(slot);
+}
+
+
+static int disable_slot (struct hotplug_slot *hotplug_slot)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	return shpchp_disable_slot(slot);
+}
+
+
+static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
+{
+	return 0;
+}
+
+
+static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_power_status(slot, value);
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;power_status;
+
+	return 0;
+}
+
+static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_attention_status(slot, value);
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;attention_status;
+
+	return 0;
+}
+
+static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+	
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_latch_status(slot, value);
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;latch_status;
+
+	return 0;
+}
+
+static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+
+	retval = slot-&gt;hpc_ops-&gt;get_adapter_status(slot, value);
+
+	if (retval &lt; 0)
+		*value = hotplug_slot-&gt;info-&gt;adapter_status;
+
+	return 0;
+}
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+	
+	retval = slot-&gt;hpc_ops-&gt;get_max_bus_speed(slot, value);
+	if (retval &lt; 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	int retval;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot-&gt;name);
+	
+	retval = slot-&gt;hpc_ops-&gt;get_cur_bus_speed(slot, value);
+	if (retval &lt; 0)
+		*value = PCI_SPEED_UNKNOWN;
+
+	return 0;
+}
+
+static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int rc;
+	struct controller *ctrl;
+	struct slot *t_slot;
+	int first_device_num;	/* first PCI device number supported by this SHPC */
+	int num_ctlr_slots;	/* number of slots supported by this SHPC */
+
+	ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
+	if (!ctrl) {
+		err("%s : out of memory\n", __FUNCTION__);
+		goto err_out_none;
+	}
+	memset(ctrl, 0, sizeof(struct controller));
+
+	dbg("DRV_thread pid = %d\n", current-&gt;pid);
+
+	rc = shpc_init(ctrl, pdev,
+			(php_intr_callback_t) shpchp_handle_attention_button,
+			(php_intr_callback_t) shpchp_handle_switch_change,
+			(php_intr_callback_t) shpchp_handle_presence_change,
+			(php_intr_callback_t) shpchp_handle_power_fault);
+	if (rc) {
+		dbg("%s: controller initialization failed\n", SHPC_MODULE_NAME);
+		goto err_out_free_ctrl;
+	}
+
+	dbg("%s: controller initialization success\n", __FUNCTION__);
+	ctrl-&gt;pci_dev = pdev;  /* pci_dev of the P2P bridge */
+
+	pci_set_drvdata(pdev, ctrl);
+
+	ctrl-&gt;pci_bus = kmalloc (sizeof (*ctrl-&gt;pci_bus), GFP_KERNEL);
+	if (!ctrl-&gt;pci_bus) {
+		err("out of memory\n");
+		rc = -ENOMEM;
+		goto err_out_unmap_mmio_region;
+	}
+	
+	memcpy (ctrl-&gt;pci_bus, pdev-&gt;bus, sizeof (*ctrl-&gt;pci_bus));
+	ctrl-&gt;bus = pdev-&gt;bus-&gt;number;
+	ctrl-&gt;slot_bus = pdev-&gt;subordinate-&gt;number;
+
+	ctrl-&gt;device = PCI_SLOT(pdev-&gt;devfn);
+	ctrl-&gt;function = PCI_FUNC(pdev-&gt;devfn);
+	dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", ctrl-&gt;bus, ctrl-&gt;device, ctrl-&gt;function, pdev-&gt;irq);
+
+	/*
+	 *	Save configuration headers for this and subordinate PCI buses
+	 */
+
+	rc = get_ctlr_slot_config(ctrl);
+	if (rc) {
+		err(msg_initialization_err, rc);
+		goto err_out_free_ctrl_bus;
+	}
+	first_device_num = ctrl-&gt;slot_device_offset;
+	num_ctlr_slots = ctrl-&gt;num_slots;
+
+	/* Store PCI Config Space for all devices on this bus */
+	rc = shpchp_save_config(ctrl, ctrl-&gt;slot_bus, num_ctlr_slots, first_device_num);
+	if (rc) {
+		err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc);
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Get IO, memory, and IRQ resources for new devices */
+	rc = shpchprm_find_available_resources(ctrl);
+	ctrl-&gt;add_support = !rc;
+	
+	if (rc) {
+		dbg("shpchprm_find_available_resources = %#x\n", rc);
+		err("unable to locate PCI configuration resources for hot plug add.\n");
+		goto err_out_free_ctrl_bus;
+	}
+
+	/* Setup the slot information structures */
+	rc = init_slots(ctrl);
+	if (rc) {
+		err(msg_initialization_err, 6);
+		goto err_out_free_ctrl_slot;
+	}
+
+	/* Now hpc_functions (slot-&gt;hpc_ops-&gt;functions) are ready  */
+	t_slot = shpchp_find_slot(ctrl, first_device_num);
+
+	/* Check for operation bus speed */
+	rc = t_slot-&gt;hpc_ops-&gt;get_cur_bus_speed(t_slot, &amp;ctrl-&gt;speed);
+	dbg("%s: t_slot-&gt;hp_slot %x\n", __FUNCTION__,t_slot-&gt;hp_slot);
+
+	if (rc || ctrl-&gt;speed == PCI_SPEED_UNKNOWN) {
+		err(SHPC_MODULE_NAME ": Can't get current bus speed. Set to 33MHz PCI.\n");
+		ctrl-&gt;speed = PCI_SPEED_33MHz;
+	}
+
+	/* Finish setting up the hot plug ctrl device */
+	ctrl-&gt;next_event = 0;
+
+	if (!shpchp_ctrl_list) {
+		shpchp_ctrl_list = ctrl;
+		ctrl-&gt;next = NULL;
+	} else {
+		ctrl-&gt;next = shpchp_ctrl_list;
+		shpchp_ctrl_list = ctrl;
+	}
+
+	shpchp_create_ctrl_files(ctrl);
+
+	return 0;
+
+err_out_free_ctrl_slot:
+	cleanup_slots(ctrl);
+err_out_free_ctrl_bus:
+	kfree(ctrl-&gt;pci_bus);
+err_out_unmap_mmio_region:
+	ctrl-&gt;hpc_ops-&gt;release_ctlr(ctrl);
+err_out_free_ctrl:
+	kfree(ctrl);
+err_out_none:
+	return -ENODEV;
+}
+
+
+static int shpc_start_thread(void)
+{
+	int loop;
+	int retval = 0;
+	
+	dbg("Initialize + Start the notification/polling mechanism \n");
+
+	retval = shpchp_event_start_thread();
+	if (retval) {
+		dbg("shpchp_event_start_thread() failed\n");
+		return retval;
+	}
+
+	dbg("Initialize slot lists\n");
+	/* One slot list for each bus in the system */
+	for (loop = 0; loop &lt; 256; loop++) {
+		shpchp_slot_list[loop] = NULL;
+	}
+
+	return retval;
+}
+
+
+static void unload_shpchpd(void)
+{
+	struct pci_func *next;
+	struct pci_func *TempSlot;
+	int loop;
+	struct controller *ctrl;
+	struct controller *tctrl;
+	struct pci_resource *res;
+	struct pci_resource *tres;
+
+	ctrl = shpchp_ctrl_list;
+
+	while (ctrl) {
+		cleanup_slots(ctrl);
+
+		res = ctrl-&gt;io_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		res = ctrl-&gt;mem_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		res = ctrl-&gt;p_mem_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		res = ctrl-&gt;bus_head;
+		while (res) {
+			tres = res;
+			res = res-&gt;next;
+			kfree(tres);
+		}
+
+		kfree (ctrl-&gt;pci_bus);
+
+		dbg("%s: calling release_ctlr\n", __FUNCTION__);
+		ctrl-&gt;hpc_ops-&gt;release_ctlr(ctrl);
+
+		tctrl = ctrl;
+		ctrl = ctrl-&gt;next;
+
+		kfree(tctrl);
+	}
+
+	for (loop = 0; loop &lt; 256; loop++) {
+		next = shpchp_slot_list[loop];
+		while (next != NULL) {
+			res = next-&gt;io_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			res = next-&gt;mem_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			res = next-&gt;p_mem_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			res = next-&gt;bus_head;
+			while (res) {
+				tres = res;
+				res = res-&gt;next;
+				kfree(tres);
+			}
+
+			TempSlot = next;
+			next = next-&gt;next;
+			kfree(TempSlot);
+		}
+	}
+
+	/* Stop the notification mechanism */
+	shpchp_event_stop_thread();
+
+}
+
+
+static struct pci_device_id shpcd_pci_tbl[] = {
+	{
+	.class =        ((PCI_CLASS_BRIDGE_PCI &lt;&lt; 8) | 0x00),
+	.class_mask =	~0,
+	.vendor =       PCI_ANY_ID,
+	.device =       PCI_ANY_ID,
+	.subvendor =    PCI_ANY_ID,
+	.subdevice =    PCI_ANY_ID,
+	},
+	
+	{ /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE(pci, shpcd_pci_tbl);
+
+
+
+static struct pci_driver shpc_driver = {
+	.name =		SHPC_MODULE_NAME,
+	.id_table =	shpcd_pci_tbl,
+	.probe =	shpc_probe,
+	/* remove:	shpc_remove_one, */
+};
+
+
+
+static int __init shpcd_init(void)
+{
+	int retval = 0;
+
+#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
+	shpchp_poll_mode = 1;
+#endif
+
+	retval = shpc_start_thread();
+	if (retval)
+		goto error_hpc_init;
+
+	retval = shpchprm_init(PCI);
+	if (!retval) {
+		retval = pci_module_init(&amp;shpc_driver);
+		dbg("%s: pci_module_init = %d\n", __FUNCTION__, retval);
+		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+	}
+
+error_hpc_init:
+	if (retval) {
+		shpchprm_cleanup();
+		shpchp_event_stop_thread();
+	} else
+		shpchprm_print_pirt();
+
+	return retval;
+}
+
+static void __exit shpcd_cleanup(void)
+{
+	dbg("unload_shpchpd()\n");
+	unload_shpchpd();
+
+	shpchprm_cleanup();
+
+	dbg("pci_unregister_driver\n");
+	pci_unregister_driver(&amp;shpc_driver);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
+}
+
+
+module_init(shpcd_init);
+module_exit(shpcd_cleanup);
+
+
diff -puN /dev/null drivers/pci/hotplug/shpchp_ctrl.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchp_ctrl.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,3055 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/interrupt.h&gt;
+#include &lt;linux/delay.h&gt;
+#include &lt;linux/wait.h&gt;
+#include &lt;linux/smp_lock.h&gt;
+#include &lt;linux/pci.h&gt;
+#include "shpchp.h"
+#include "shpchprm.h"
+
+static u32 configure_new_device(struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static int configure_new_function( struct controller *ctrl, struct pci_func *func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev);
+static void interrupt_event_handler(struct controller *ctrl);
+
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
+static int event_finished;
+static unsigned long pushbutton_pending;	/* = 0 */
+
+u8 shpchp_disk_irq;
+u8 shpchp_nic_irq;
+
+u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Attention Button Change */
+	dbg("shpchp:  Attention button interrupt received.\n");
+	
+	func = shpchp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread what to do */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+
+	/*
+	 *  Button pressed - See if need to TAKE ACTION!!!
+	 */
+	info("Button pressed on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+	taskInfo-&gt;event_type = INT_BUTTON_PRESS;
+
+	if ((p_slot-&gt;state == BLINKINGON_STATE)
+	    || (p_slot-&gt;state == BLINKINGOFF_STATE)) {
+		/* Cancel if we are still blinking; this means that we press the
+		 * attention again before the 5 sec. limit expires to cancel hot-add
+		 * or hot-remove
+		 */
+		taskInfo-&gt;event_type = INT_BUTTON_CANCEL;
+		info("Button cancel on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+	} else if ((p_slot-&gt;state == POWERON_STATE)
+		   || (p_slot-&gt;state == POWEROFF_STATE)) {
+		/* Ignore if the slot is on power-on or power-off state; this 
+		 * means that the previous attention button action to hot-add or
+		 * hot-remove is undergoing
+		 */
+		taskInfo-&gt;event_type = INT_BUTTON_IGNORE;
+		info("Button ignore on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+	}
+
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return 0;
+
+}
+
+u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	u8 getstatus;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Switch Change */
+	dbg("shpchp:  Switch interrupt received.\n");
+
+	func = shpchp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+
+	if (!getstatus) {
+		/*
+		 * Switch opened
+		 */
+		info("Latch open on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		func-&gt;switch_save = 0;
+		taskInfo-&gt;event_type = INT_SWITCH_OPEN;
+	} else {
+		/*
+		 *  Switch closed
+		 */
+		info("Latch close on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		func-&gt;switch_save = 0x10;
+		taskInfo-&gt;event_type = INT_SWITCH_CLOSE;
+	}
+
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	/*u8 temp_byte;*/
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Presence Change */
+	dbg("shpchp:  Presence/Notify input change.\n");
+
+	func = shpchp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	/* 
+	 * Save the presence state
+	 */
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	if (func-&gt;presence_save) {
+		/*
+		 * Card Present
+		 */
+		taskInfo-&gt;event_type = INT_PRESENCE_ON;
+	} else {
+		/*
+		 * Not Present
+		 */
+		taskInfo-&gt;event_type = INT_PRESENCE_OFF;
+	}
+
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
+{
+	struct controller *ctrl = (struct controller *) inst_id;
+	struct slot *p_slot;
+	u8 rc = 0;
+	struct pci_func *func;
+	struct event_info *taskInfo;
+
+	/* Power fault */
+	dbg("shpchp:  Power fault interrupt received.\n");
+
+	func = shpchp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+	/* This is the structure that tells the worker thread
+	 * what to do
+	 */
+	taskInfo = &amp;(ctrl-&gt;event_queue[ctrl-&gt;next_event]);
+	ctrl-&gt;next_event = (ctrl-&gt;next_event + 1) % 10;
+	taskInfo-&gt;hp_slot = hp_slot;
+
+	rc++;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	if ( !(p_slot-&gt;hpc_ops-&gt;query_power_fault(p_slot))) {
+		/*
+		 * Power fault Cleared
+		 */
+		info("Power fault cleared on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		func-&gt;status = 0x00;
+		taskInfo-&gt;event_type = INT_POWER_FAULT_CLEAR;
+	} else {
+		/*
+		 *   Power fault
+		 */
+		info("Power fault on Slot(%d)\n", ctrl-&gt;first_slot + hp_slot);
+		taskInfo-&gt;event_type = INT_POWER_FAULT;
+		/* set power fault status for this board */
+		func-&gt;status = 0xFF;
+		info("power fault bit %x set\n", hp_slot);
+	}
+	if (rc)
+		up(&amp;event_semaphore);	/* signal event thread that new event is posted */
+
+	return rc;
+}
+
+
+/*
+ * sort_by_size
+ *
+ * Sorts nodes on the list by their length.
+ * Smallest first.
+ *
+ */
+static int sort_by_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)-&gt;next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)-&gt;next) &amp;&amp;
+		    ((*head)-&gt;length &gt; (*head)-&gt;next-&gt;length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)-&gt;next;
+			current_res-&gt;next = (*head)-&gt;next;
+			(*head)-&gt;next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res-&gt;next &amp;&amp; current_res-&gt;next-&gt;next) {
+			if (current_res-&gt;next-&gt;length &gt; current_res-&gt;next-&gt;next-&gt;length) {
+				out_of_order++;
+				next_res = current_res-&gt;next;
+				current_res-&gt;next = current_res-&gt;next-&gt;next;
+				current_res = current_res-&gt;next;
+				next_res-&gt;next = current_res-&gt;next;
+				current_res-&gt;next = next_res;
+			} else
+				current_res = current_res-&gt;next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * sort_by_max_size
+ *
+ * Sorts nodes on the list by their length.
+ * Largest first.
+ *
+ */
+static int sort_by_max_size(struct pci_resource **head)
+{
+	struct pci_resource *current_res;
+	struct pci_resource *next_res;
+	int out_of_order = 1;
+
+	if (!(*head))
+		return(1);
+
+	if (!((*head)-&gt;next))
+		return(0);
+
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)-&gt;next) &amp;&amp;
+		    ((*head)-&gt;length &lt; (*head)-&gt;next-&gt;length)) {
+			out_of_order++;
+			current_res = *head;
+			*head = (*head)-&gt;next;
+			current_res-&gt;next = (*head)-&gt;next;
+			(*head)-&gt;next = current_res;
+		}
+
+		current_res = *head;
+
+		while (current_res-&gt;next &amp;&amp; current_res-&gt;next-&gt;next) {
+			if (current_res-&gt;next-&gt;length &lt; current_res-&gt;next-&gt;next-&gt;length) {
+				out_of_order++;
+				next_res = current_res-&gt;next;
+				current_res-&gt;next = current_res-&gt;next-&gt;next;
+				current_res = current_res-&gt;next;
+				next_res-&gt;next = current_res-&gt;next;
+				current_res-&gt;next = next_res;
+			} else
+				current_res = current_res-&gt;next;
+		}
+	}  /* End of out_of_order loop */
+
+	return(0);
+}
+
+
+/*
+ * do_pre_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 rc;
+	u32 temp_dword;
+	dbg("do_pre_bridge_resource_split\n");
+
+	if (!(*head) || !(*orig_head))
+		return(NULL);
+
+	rc = shpchp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	if ((*head)-&gt;base != (*orig_head)-&gt;base)
+		return(NULL);
+
+	if ((*head)-&gt;length == (*orig_head)-&gt;length)
+		return(NULL);
+
+
+	/* If we got here, there the bridge requires some of the resource, but
+	 *  we may be able to split some off of the front
+	 */	
+	node = *head;
+
+	if (node-&gt;length &amp; (alignment -1)) {
+		/* This one isn't an aligned length, so we'll make a new entry
+		 * and split it up.
+		 */
+		split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!split_node)
+			return(NULL);
+
+		temp_dword = (node-&gt;length | (alignment-1)) + 1 - alignment;
+
+		split_node-&gt;base = node-&gt;base;
+		split_node-&gt;length = temp_dword;
+
+		node-&gt;length -= temp_dword;
+		node-&gt;base += split_node-&gt;length;
+
+		/* Put it in the list */
+		*head = split_node;
+		split_node-&gt;next = node;
+	}
+
+	if (node-&gt;length &lt; alignment) {
+		return(NULL);
+	}
+
+	/* Now unlink it */
+	if (*head == node) {
+		*head = node-&gt;next;
+		node-&gt;next = NULL;
+	} else {
+		prevnode = *head;
+		while (prevnode-&gt;next != node)
+			prevnode = prevnode-&gt;next;
+
+		prevnode-&gt;next = node-&gt;next;
+		node-&gt;next = NULL;
+	}
+
+	return(node);
+}
+
+
+/*
+ * do_bridge_resource_split
+ *
+ *	Returns zero or one node of resources that aren't in use
+ *
+ */
+static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment)
+{
+	struct pci_resource *prevnode = NULL;
+	struct pci_resource *node;
+	u32 rc;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	rc = shpchp_resource_sort_and_combine(head);
+
+	if (rc)
+		return(NULL);
+
+	node = *head;
+
+	while (node-&gt;next) {
+		prevnode = node;
+		node = node-&gt;next;
+		kfree(prevnode);
+	}
+
+	if (node-&gt;length &lt; alignment) {
+		kfree(node);
+		return(NULL);
+	}
+
+	if (node-&gt;base &amp; (alignment - 1)) {
+		/* Short circuit if adjusted size is too small */
+		temp_dword = (node-&gt;base | (alignment-1)) + 1;
+		if ((node-&gt;length - (temp_dword - node-&gt;base)) &lt; alignment) {
+			kfree(node);
+			return(NULL);
+		}
+
+		node-&gt;length -= (temp_dword - node-&gt;base);
+		node-&gt;base = temp_dword;
+	}
+
+	if (node-&gt;length &amp; (alignment - 1)) {
+		/* There's stuff in use after this node */
+		kfree(node);
+		return(NULL);
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_io_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length that is not in the
+ * ISA aliasing window.  If it finds a node larger than "size"
+ * it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node = NULL;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( shpchp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node-&gt;next) {
+		if (node-&gt;length &lt; size)
+			continue;
+
+		if (node-&gt;base &amp; (size - 1)) {
+			/* This one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node-&gt;base | (size-1)) + 1;
+
+			/*/ Short circuit if adjusted size is too small */
+			if ((node-&gt;length - (temp_dword - node-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base;
+			split_node-&gt;length = temp_dword - node-&gt;base;
+			node-&gt;base = temp_dword;
+			node-&gt;length -= split_node-&gt;length;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node-&gt;length &gt; size) {
+			/* This one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base + size;
+			split_node-&gt;length = node-&gt;length - size;
+			node-&gt;length = size;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		}  /* End of too big on top end */
+
+		/* For IO make sure it's not in the ISA aliasing space */
+		if (node-&gt;base &amp; 0x300L)
+			continue;
+
+		/* If we got here, then it is the right size 
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node-&gt;next;
+		} else {
+			prevnode = *head;
+			while (prevnode-&gt;next != node)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = node-&gt;next;
+		}
+		node-&gt;next = NULL;
+		/* Stop looping */
+		break;
+	}
+
+	return(node);
+}
+
+
+/*
+ * get_max_resource
+ *
+ * Gets the largest node that is at least "size" big from the
+ * list pointed to by head.  It aligns the node on top and bottom
+ * to "size" alignment before returning it.
+ * J.I. modified to put max size limits of; 64M-&gt;32M-&gt;16M-&gt;8M-&gt;4M-&gt;1M
+ *  This is needed to avoid allocating entire ACPI _CRS res to one child bridge/slot.
+ */
+static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *max;
+	struct pci_resource *temp;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+	u32 max_size[] = { 0x4000000, 0x2000000, 0x1000000, 0x0800000, 0x0400000, 0x0200000, 0x0100000, 0x00 };
+	int i;
+
+	if (!(*head))
+		return(NULL);
+
+	if (shpchp_resource_sort_and_combine(head))
+		return(NULL);
+
+	if (sort_by_max_size(head))
+		return(NULL);
+
+	for (max = *head;max; max = max-&gt;next) {
+
+		/* If not big enough we could probably just bail, 
+		   instead we'll continue to the next. */
+		if (max-&gt;length &lt; size)
+			continue;
+
+		if (max-&gt;base &amp; (size - 1)) {
+			/* This one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (max-&gt;base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((max-&gt;length - (temp_dword - max-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = max-&gt;base;
+			split_node-&gt;length = temp_dword - max-&gt;base;
+			max-&gt;base = temp_dword;
+			max-&gt;length -= split_node-&gt;length;
+
+			/* Put it next in the list */
+			split_node-&gt;next = max-&gt;next;
+			max-&gt;next = split_node;
+		}
+
+		if ((max-&gt;base + max-&gt;length) &amp; (size - 1)) {
+			/* This one isn't end aligned properly at the top
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+			temp_dword = ((max-&gt;base + max-&gt;length) &amp; ~(size - 1));
+			split_node-&gt;base = temp_dword;
+			split_node-&gt;length = max-&gt;length + max-&gt;base
+					     - split_node-&gt;base;
+			max-&gt;length -= split_node-&gt;length;
+
+			/* Put it in the list */
+			split_node-&gt;next = max-&gt;next;
+			max-&gt;next = split_node;
+		}
+
+		/* Make sure it didn't shrink too much when we aligned it */
+		if (max-&gt;length &lt; size)
+			continue;
+
+		for ( i = 0; max_size[i] &gt; size; i++) {
+			if (max-&gt;length &gt; max_size[i]) {
+				split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!split_node)
+					break;	/* return (NULL); */
+				split_node-&gt;base = max-&gt;base + max_size[i];
+				split_node-&gt;length = max-&gt;length - max_size[i];
+				max-&gt;length = max_size[i];
+				/* Put it next in the list */
+				split_node-&gt;next = max-&gt;next;
+				max-&gt;next = split_node;
+				break;
+			}
+		}
+
+		/* Now take it out of the list */
+		temp = (struct pci_resource*) *head;
+		if (temp == max) {
+			*head = max-&gt;next;
+		} else {
+			while (temp &amp;&amp; temp-&gt;next != max) {
+				temp = temp-&gt;next;
+			}
+
+			temp-&gt;next = max-&gt;next;
+		}
+
+		max-&gt;next = NULL;
+		return(max);
+	}
+
+	/* If we get here, we couldn't find one */
+	return(NULL);
+}
+
+
+/*
+ * get_resource
+ *
+ * this function sorts the resource list by size and then
+ * returns the first node of "size" length.  If it finds a node
+ * larger than "size" it will split it up.
+ *
+ * size must be a power of two.
+ */
+static struct pci_resource *get_resource (struct pci_resource **head, u32 size)
+{
+	struct pci_resource *prevnode;
+	struct pci_resource *node;
+	struct pci_resource *split_node;
+	u32 temp_dword;
+
+	if (!(*head))
+		return(NULL);
+
+	if ( shpchp_resource_sort_and_combine(head) )
+		return(NULL);
+
+	if ( sort_by_size(head) )
+		return(NULL);
+
+	for (node = *head; node; node = node-&gt;next) {
+		dbg("%s: req_size =0x%x node=%p, base=0x%x, length=0x%x\n",
+		    __FUNCTION__, size, node, node-&gt;base, node-&gt;length);
+		if (node-&gt;length &lt; size)
+			continue;
+
+		if (node-&gt;base &amp; (size - 1)) {
+			dbg("%s: not aligned\n", __FUNCTION__);
+			/* this one isn't base aligned properly
+			   so we'll make a new entry and split it up */
+			temp_dword = (node-&gt;base | (size-1)) + 1;
+
+			/* Short circuit if adjusted size is too small */
+			if ((node-&gt;length - (temp_dword - node-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base;
+			split_node-&gt;length = temp_dword - node-&gt;base;
+			node-&gt;base = temp_dword;
+			node-&gt;length -= split_node-&gt;length;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		} /* End of non-aligned base */
+
+		/* Don't need to check if too small since we already did */
+		if (node-&gt;length &gt; size) {
+			dbg("%s: too big\n", __FUNCTION__);
+			/* this one is longer than we need
+			   so we'll make a new entry and split it up */
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+			if (!split_node)
+				return(NULL);
+
+			split_node-&gt;base = node-&gt;base + size;
+			split_node-&gt;length = node-&gt;length - size;
+			node-&gt;length = size;
+
+			/* Put it in the list */
+			split_node-&gt;next = node-&gt;next;
+			node-&gt;next = split_node;
+		}  /* End of too big on top end */
+
+		dbg("%s: got one!!!\n", __FUNCTION__);
+		/* If we got here, then it is the right size
+		   Now take it out of the list */
+		if (*head == node) {
+			*head = node-&gt;next;
+		} else {
+			prevnode = *head;
+			while (prevnode-&gt;next != node)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = node-&gt;next;
+		}
+		node-&gt;next = NULL;
+		/* Stop looping */
+		break;
+	}
+	return(node);
+}
+
+
+/*
+ * shpchp_resource_sort_and_combine
+ *
+ * Sorts all of the nodes in the list in ascending order by
+ * their base addresses.  Also does garbage collection by
+ * combining adjacent nodes.
+ *
+ * returns 0 if success
+ */
+int shpchp_resource_sort_and_combine(struct pci_resource **head)
+{
+	struct pci_resource *node1;
+	struct pci_resource *node2;
+	int out_of_order = 1;
+
+	dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head);
+
+	if (!(*head))
+		return(1);
+
+	dbg("*head-&gt;next = %p\n",(*head)-&gt;next);
+
+	if (!(*head)-&gt;next)
+		return(0);	/* only one item on the list, already sorted! */
+
+	dbg("*head-&gt;base = 0x%x\n",(*head)-&gt;base);
+	dbg("*head-&gt;next-&gt;base = 0x%x\n",(*head)-&gt;next-&gt;base);
+	while (out_of_order) {
+		out_of_order = 0;
+
+		/* Special case for swapping list head */
+		if (((*head)-&gt;next) &amp;&amp;
+		    ((*head)-&gt;base &gt; (*head)-&gt;next-&gt;base)) {
+			node1 = *head;
+			(*head) = (*head)-&gt;next;
+			node1-&gt;next = (*head)-&gt;next;
+			(*head)-&gt;next = node1;
+			out_of_order++;
+		}
+
+		node1 = (*head);
+
+		while (node1-&gt;next &amp;&amp; node1-&gt;next-&gt;next) {
+			if (node1-&gt;next-&gt;base &gt; node1-&gt;next-&gt;next-&gt;base) {
+				out_of_order++;
+				node2 = node1-&gt;next;
+				node1-&gt;next = node1-&gt;next-&gt;next;
+				node1 = node1-&gt;next;
+				node2-&gt;next = node1-&gt;next;
+				node1-&gt;next = node2;
+			} else
+				node1 = node1-&gt;next;
+		}
+	}  /* End of out_of_order loop */
+
+	node1 = *head;
+
+	while (node1 &amp;&amp; node1-&gt;next) {
+		if ((node1-&gt;base + node1-&gt;length) == node1-&gt;next-&gt;base) {
+			/* Combine */
+			dbg("8..\n");
+			node1-&gt;length += node1-&gt;next-&gt;length;
+			node2 = node1-&gt;next;
+			node1-&gt;next = node1-&gt;next-&gt;next;
+			kfree(node2);
+		} else
+			node1 = node1-&gt;next;
+	}
+
+	return(0);
+}
+
+
+/**
+ * shpchp_slot_create - Creates a node and adds it to the proper bus.
+ * @busnumber - bus where new node is to be located
+ *
+ * Returns pointer to the new node or NULL if unsuccessful
+ */
+struct pci_func *shpchp_slot_create(u8 busnumber)
+{
+	struct pci_func *new_slot;
+	struct pci_func *next;
+
+	new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL);
+
+	if (new_slot == NULL) {
+		return(new_slot);
+	}
+
+	memset(new_slot, 0, sizeof(struct pci_func));
+
+	new_slot-&gt;next = NULL;
+	new_slot-&gt;configured = 1;
+
+	if (shpchp_slot_list[busnumber] == NULL) {
+		shpchp_slot_list[busnumber] = new_slot;
+	} else {
+		next = shpchp_slot_list[busnumber];
+		while (next-&gt;next != NULL)
+			next = next-&gt;next;
+		next-&gt;next = new_slot;
+	}
+	return(new_slot);
+}
+
+
+/*
+ * slot_remove - Removes a node from the linked list of slots.
+ * @old_slot: slot to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int slot_remove(struct pci_func * old_slot)
+{
+	struct pci_func *next;
+
+	if (old_slot == NULL)
+		return(1);
+
+	next = shpchp_slot_list[old_slot-&gt;bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == old_slot) {
+		shpchp_slot_list[old_slot-&gt;bus] = old_slot-&gt;next;
+		shpchp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	}
+
+	while ((next-&gt;next != old_slot) &amp;&amp; (next-&gt;next != NULL)) {
+		next = next-&gt;next;
+	}
+
+	if (next-&gt;next == old_slot) {
+		next-&gt;next = old_slot-&gt;next;
+		shpchp_destroy_board_resources(old_slot);
+		kfree(old_slot);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * bridge_slot_remove - Removes a node from the linked list of slots.
+ * @bridge: bridge to remove
+ *
+ * Returns 0 if successful, !0 otherwise.
+ */
+static int bridge_slot_remove(struct pci_func *bridge)
+{
+	u8 subordinateBus, secondaryBus;
+	u8 tempBus;
+	struct pci_func *next;
+
+	if (bridge == NULL)
+		return(1);
+
+	secondaryBus = (bridge-&gt;config_space[0x06] &gt;&gt; 8) &amp; 0xFF;
+	subordinateBus = (bridge-&gt;config_space[0x06] &gt;&gt; 16) &amp; 0xFF;
+
+	for (tempBus = secondaryBus; tempBus &lt;= subordinateBus; tempBus++) {
+		next = shpchp_slot_list[tempBus];
+
+		while (!slot_remove(next)) {
+			next = shpchp_slot_list[tempBus];
+		}
+	}
+
+	next = shpchp_slot_list[bridge-&gt;bus];
+
+	if (next == NULL) {
+		return(1);
+	}
+
+	if (next == bridge) {
+		shpchp_slot_list[bridge-&gt;bus] = bridge-&gt;next;
+		kfree(bridge);
+		return(0);
+	}
+
+	while ((next-&gt;next != bridge) &amp;&amp; (next-&gt;next != NULL)) {
+		next = next-&gt;next;
+	}
+
+	if (next-&gt;next == bridge) {
+		next-&gt;next = bridge-&gt;next;
+		kfree(bridge);
+		return(0);
+	} else
+		return(2);
+}
+
+
+/**
+ * shpchp_slot_find - Looks for a node by bus, and device, multiple functions accessed
+ * @bus: bus to find
+ * @device: device to find
+ * @index: is 0 for first function found, 1 for the second...
+ *
+ * Returns pointer to the node if successful, %NULL otherwise.
+ */
+struct pci_func *shpchp_slot_find(u8 bus, u8 device, u8 index)
+{
+	int found = -1;
+	struct pci_func *func;
+
+	func = shpchp_slot_list[bus];
+
+	if ((func == NULL) || ((func-&gt;device == device) &amp;&amp; (index == 0)))
+		return(func);
+
+	if (func-&gt;device == device)
+		found++;
+
+	while (func-&gt;next != NULL) {
+		func = func-&gt;next;
+
+		if (func-&gt;device == device)
+			found++;
+
+		if (found == index)
+			return(func);
+	}
+
+	return(NULL);
+}
+
+static int is_bridge(struct pci_func * func)
+{
+	/* Check the header type */
+	if (((func-&gt;config_space[0x03] &gt;&gt; 16) &amp; 0xFF) == 0x01)
+		return 1;
+	else
+		return 0;
+}
+
+
+/* The following routines constitute the bulk of the 
+   hotplug controller logic
+ */
+
+
+/**
+ * board_added - Called after a board has been added to the system.
+ *
+ * Turns power on for the board
+ * Configures board
+ *
+ */
+static u32 board_added(struct pci_func * func, struct controller * ctrl)
+{
+	u8 hp_slot, slot;
+	u8 slots_not_empty = 0;
+	int index;
+	u32 temp_register = 0xFFFFFFFF;
+	u32 retval, rc = 0;
+	struct pci_func *new_func = NULL;
+	struct pci_func *t_func = NULL;
+	struct slot *p_slot, *pslot;
+	struct resource_lists res_lists;
+	enum pci_bus_speed adapter_speed, bus_speed, max_bus_speed;
+	u8 pi, mode;
+
+	p_slot = shpchp_find_slot(ctrl, func-&gt;device);
+	hp_slot = func-&gt;device - ctrl-&gt;slot_device_offset;
+
+	dbg("%s: func-&gt;device, slot_offset, hp_slot = %d, %d ,%d\n", __FUNCTION__, func-&gt;device, ctrl-&gt;slot_device_offset, hp_slot);
+
+	/* Wait for exclusive access to hardware */
+	down(&amp;ctrl-&gt;crit_sect);
+
+	/* Power on slot without connecting to bus */
+	rc = p_slot-&gt;hpc_ops-&gt;power_on_slot(p_slot);
+	if (rc) {
+		err("%s: Failed to power on slot\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return -1;
+	}
+			
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+	
+	rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to power on slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return -1;
+	}
+
+	rc = p_slot-&gt;hpc_ops-&gt;get_adapter_speed(p_slot, &amp;adapter_speed);
+	/* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */
+	/* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC,  0xa = PCI-X 133 Mhz 266, */
+	/* 0xd = PCI-X 133 Mhz 533 */
+	/* This encoding is different from the one used in cur_bus_speed &amp; */
+	/* max_bus_speed */
+
+	if (rc  || adapter_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+
+	rc = p_slot-&gt;hpc_ops-&gt;get_cur_bus_speed(p_slot, &amp;bus_speed);
+	if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get bus operation speed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return WRONG_BUS_FREQUENCY;
+	}
+
+	rc = p_slot-&gt;hpc_ops-&gt;get_max_bus_speed(p_slot, &amp;max_bus_speed);
+	if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
+		err("%s: Can't get max bus operation speed\n", __FUNCTION__);
+		max_bus_speed = bus_speed;
+	}
+
+	/* Done with exclusive hardware access */
+	up(&amp;ctrl-&gt;crit_sect);
+
+	rc  = p_slot-&gt;hpc_ops-&gt;get_prog_int(p_slot, &amp;pi);
+	if (rc) {
+		err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
+		pi = 1;
+	}
+	if (pi == 2) {
+		for ( slot = 0; slot &lt; ctrl-&gt;num_slots; slot++) {
+			if (slot != hp_slot) {
+				pslot = shpchp_find_slot(ctrl, slot + ctrl-&gt;slot_device_offset);
+				t_func = shpchp_slot_find(pslot-&gt;bus, pslot-&gt;device, 0);
+				slots_not_empty |= t_func-&gt;is_a_board;
+			}
+		}
+
+		switch (adapter_speed) {
+		case PCI_SPEED_133MHz_PCIX_533:	
+		case PCI_SPEED_133MHz_PCIX_266:
+			if ((( bus_speed &lt; 0xa ) || (bus_speed &lt; 0xd)) &amp;&amp; (max_bus_speed &gt; bus_speed) &amp;&amp;
+				((max_bus_speed &lt;= 0xa) || (max_bus_speed &lt;= 0xd)) &amp;&amp; (!slots_not_empty)) {
+			
+				/* Wait for exclusive access to hardware */
+				down(&amp;ctrl-&gt;crit_sect);
+
+				rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+				if (rc) {
+					err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				
+				/* Wait for the command to complete */
+				wait_for_ctrl_irq (ctrl);
+		
+				rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+				if (rc) {
+					err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+							  __FUNCTION__);
+					err("%s: Error code (%d)\n", __FUNCTION__, rc);
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Done with exclusive hardware access */
+				up(&amp;ctrl-&gt;crit_sect);
+			}
+			break;
+		case PCI_SPEED_133MHz_PCIX_ECC:
+		case PCI_SPEED_133MHz_PCIX:
+
+			rc = p_slot-&gt;hpc_ops-&gt;get_mode1_ECC_cap(p_slot, &amp;mode);
+
+			if (rc) {
+				err("%s: PI is 1 \n", __FUNCTION__);
+				return WRONG_BUS_FREQUENCY;
+			}
+
+			if (mode) { /* Bus - Mode 1 ECC */
+
+				if (bus_speed &gt; 0x7)  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed &lt; 0x7) &amp;&amp; (max_bus_speed &lt;= 0x7) &amp;&amp;
+					(bus_speed &lt; max_bus_speed) &amp;&amp; (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+				}
+			} else {
+				if ((bus_speed &gt; 0x4) || (max_bus_speed &gt; 0x4))  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed &lt; 0x4) &amp;&amp; (max_bus_speed &lt;= 0x4) &amp;&amp;
+					(bus_speed &lt; max_bus_speed) &amp;&amp; (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+				}
+			}
+			break;
+		case PCI_SPEED_66MHz_PCIX_ECC:
+		case PCI_SPEED_66MHz_PCIX:
+
+			rc = p_slot-&gt;hpc_ops-&gt;get_mode1_ECC_cap(p_slot, &amp;mode);
+
+			if (rc) {
+				err("%s: PI is 1 \n", __FUNCTION__);
+				return WRONG_BUS_FREQUENCY;
+			}
+
+			if (mode) { /* Bus - Mode 1 ECC */
+
+				if (bus_speed &gt; 0x5)  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed &lt; 0x5) &amp;&amp; (max_bus_speed &lt;= 0x5) &amp;&amp;
+					(bus_speed &lt; max_bus_speed) &amp;&amp; (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+				}
+			} else {
+				if ((bus_speed &gt; 0x2) || (max_bus_speed &gt; 0x2))  {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+
+				if ((bus_speed &lt; 0x2) &amp;&amp; (max_bus_speed &lt;= 0x2) &amp;&amp;
+					(bus_speed &lt; max_bus_speed) &amp;&amp; (!slots_not_empty)) {
+
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+							  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);				
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+				}
+			}
+			break;
+		case PCI_SPEED_66MHz:
+			if (bus_speed &gt; 0x1) {
+				err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+				return WRONG_BUS_FREQUENCY;
+			}
+			if (bus_speed == 0x1)
+				;
+			if ((bus_speed == 0x0) &amp;&amp; ( max_bus_speed == 0x1))  {
+				/* Wait for exclusive access to hardware */
+				down(&amp;ctrl-&gt;crit_sect);
+
+				rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+				if (rc) {
+					err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				
+				/* Wait for the command to complete */
+				wait_for_ctrl_irq (ctrl);
+		
+				rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+				if (rc) {
+					err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+							  __FUNCTION__);
+					err("%s: Error code (%d)\n", __FUNCTION__, rc);
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);				
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Done with exclusive hardware access */
+				up(&amp;ctrl-&gt;crit_sect);
+			}
+			break;	
+		case PCI_SPEED_33MHz:
+			if (bus_speed &gt; 0x0) {
+				err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+				return WRONG_BUS_FREQUENCY;
+			}
+			break;
+		default:
+			err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+			return WRONG_BUS_FREQUENCY;
+		}
+	} else {
+		/* if adpater_speed == bus_speed, nothing to do here */
+		if (adapter_speed != bus_speed) {
+			for ( slot = 0; slot &lt; ctrl-&gt;num_slots; slot++) {
+				if (slot != hp_slot) {
+					pslot = shpchp_find_slot(ctrl, slot + ctrl-&gt;slot_device_offset);
+					t_func = shpchp_slot_find(pslot-&gt;bus, pslot-&gt;device, 0);
+					slots_not_empty |= t_func-&gt;is_a_board;
+				}
+			}
+
+			if (slots_not_empty != 0) { /* Other slots on the same bus are occupied */
+				if ( adapter_speed &lt; bus_speed ) {
+					err("%s: speed of bus %x and adapter %x mismatch\n", __FUNCTION__, bus_speed, adapter_speed);
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Do nothing if adapter_speed &gt;= bus_speed */
+			}
+		}
+			
+		if ((adapter_speed != bus_speed) &amp;&amp; (slots_not_empty == 0))  {
+			/* Other slots on the same bus are empty */
+			
+			rc = p_slot-&gt;hpc_ops-&gt;get_max_bus_speed(p_slot, &amp;max_bus_speed);
+			if (rc || max_bus_speed == PCI_SPEED_UNKNOWN) {
+				err("%s: Can't get max bus operation speed\n", __FUNCTION__);
+				max_bus_speed = bus_speed;
+			}
+
+			if (max_bus_speed == bus_speed) {
+				/* if adapter_speed &gt;= bus_speed, do nothing */
+				if (adapter_speed &lt; bus_speed) {
+				/* 
+				 * Try to lower bus speed to accommodate the adapter if other slots 
+				 * on the same controller are empty
+				 */
+					
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, adapter_speed);
+					if (rc) {
+						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						return WRONG_BUS_FREQUENCY;
+					}
+				
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+		
+					rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+					if (rc) {
+						err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n",
+								  __FUNCTION__);
+						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						return WRONG_BUS_FREQUENCY;
+					}
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+
+				} 
+			} else {
+				/* Wait for exclusive access to hardware */
+				down(&amp;ctrl-&gt;crit_sect);
+
+				/* max_bus_speed != bus_speed. Note: max_bus_speed should be &gt; than bus_speed */
+				if (adapter_speed &lt; max_bus_speed) 
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, adapter_speed);
+				else  
+					rc = p_slot-&gt;hpc_ops-&gt;set_bus_speed_mode(p_slot, max_bus_speed);
+				
+				if (rc) {
+					err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+					return WRONG_BUS_FREQUENCY;
+				}
+				
+				/* Wait for the command to complete */
+				wait_for_ctrl_irq (ctrl);
+		
+				rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+				if (rc) {
+					err("%s: Can't set bus speed/mode in the case of adapter &amp; bus mismatch\n", 
+						__FUNCTION__);
+					err("%s: Error code (%d)\n", __FUNCTION__, rc);
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+					return WRONG_BUS_FREQUENCY;
+				}
+				/* Done with exclusive hardware access */
+				up(&amp;ctrl-&gt;crit_sect);
+
+			}
+		}
+	}
+
+	/* Wait for exclusive access to hardware */
+	down(&amp;ctrl-&gt;crit_sect);
+
+	/* turn on board, blink green LED, turn off Amber LED */
+	rc = p_slot-&gt;hpc_ops-&gt;slot_enable(p_slot);
+	
+	if (rc) {
+		err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return rc;  
+	}
+
+	/* Done with exclusive hardware access */
+	up(&amp;ctrl-&gt;crit_sect);
+
+	/* Wait for ~1 second */
+	dbg("%s: before long_delay\n", __FUNCTION__);
+	wait_for_ctrl_irq (ctrl);
+	dbg("%s: afterlong_delay\n", __FUNCTION__);
+
+	dbg("%s: func status = %x\n", __FUNCTION__, func-&gt;status);
+	/* Check for a power fault */
+	if (func-&gt;status == 0xFF) {
+		/* power fault occurred, but it was benign */
+		temp_register = 0xFFFFFFFF;
+		dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register);
+		rc = POWER_FAILURE;
+		func-&gt;status = 0;
+	} else {
+		/* Get vendor/device ID u32 */
+		rc = pci_bus_read_config_dword (ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(func-&gt;device, func-&gt;function), 
+			PCI_VENDOR_ID, &amp;temp_register);
+		dbg("%s: pci_bus_read_config_dword returns %d\n", __FUNCTION__, rc);
+		dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register);
+
+		if (rc != 0) {
+			/* Something's wrong here */
+			temp_register = 0xFFFFFFFF;
+			dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register);
+		}
+		/* Preset return code.  It will be changed later if things go okay. */
+		rc = NO_ADAPTER_PRESENT;
+	}
+
+	/* All F's is an empty slot or an invalid board */
+	if (temp_register != 0xFFFFFFFF) {	  /* Check for a board in the slot */
+		res_lists.io_head = ctrl-&gt;io_head;
+		res_lists.mem_head = ctrl-&gt;mem_head;
+		res_lists.p_mem_head = ctrl-&gt;p_mem_head;
+		res_lists.bus_head = ctrl-&gt;bus_head;
+		res_lists.irqs = NULL;
+
+		rc = configure_new_device(ctrl, func, 0, &amp;res_lists, 0, 0);
+		dbg("%s: back from configure_new_device\n", __FUNCTION__);
+
+		ctrl-&gt;io_head = res_lists.io_head;
+		ctrl-&gt;mem_head = res_lists.mem_head;
+		ctrl-&gt;p_mem_head = res_lists.p_mem_head;
+		ctrl-&gt;bus_head = res_lists.bus_head;
+
+		shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;mem_head));
+		shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;p_mem_head));
+		shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;io_head));
+		shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;bus_head));
+
+		if (rc) {
+			/* Wait for exclusive access to hardware */
+			down(&amp;ctrl-&gt;crit_sect);
+
+			/* turn off slot, turn on Amber LED, turn off Green LED */
+			retval = p_slot-&gt;hpc_ops-&gt;slot_disable(p_slot);
+			if (retval) {
+				err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
+				/* Done with exclusive hardware access */
+				up(&amp;ctrl-&gt;crit_sect);
+				return retval;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (ctrl);
+
+			retval = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+			if (retval) {
+				err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+				/* Done with exclusive hardware access */
+				up(&amp;ctrl-&gt;crit_sect);
+				return retval;  
+			}
+
+			/* Done with exclusive hardware access */
+			up(&amp;ctrl-&gt;crit_sect);
+
+			return(rc);
+		}
+		shpchp_save_slot_config(ctrl, func);
+
+		func-&gt;status = 0;
+		func-&gt;switch_save = 0x10;
+		func-&gt;is_a_board = 0x01;
+
+		/* next, we will instantiate the linux pci_dev structures 
+		 * (with appropriate driver notification, if already present) 
+		 */
+		index = 0;
+		do {
+			new_func = shpchp_slot_find(ctrl-&gt;slot_bus, func-&gt;device, index++);
+			if (new_func &amp;&amp; !new_func-&gt;pci_dev) {
+				dbg("%s:call pci_hp_configure_dev\n", __FUNCTION__);
+				shpchp_configure_device(ctrl, new_func);
+			}
+		} while (new_func);
+
+		/* Wait for exclusive access to hardware */
+		down(&amp;ctrl-&gt;crit_sect);
+
+		p_slot-&gt;hpc_ops-&gt;green_led_on(p_slot);
+
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+
+	} else {
+		/* Wait for exclusive access to hardware */
+		down(&amp;ctrl-&gt;crit_sect);
+
+		/* turn off slot, turn on Amber LED, turn off Green LED */
+		rc = p_slot-&gt;hpc_ops-&gt;slot_disable(p_slot);
+		if (rc) {
+			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+			/* Done with exclusive hardware access */
+			up(&amp;ctrl-&gt;crit_sect);
+			return rc;
+		}
+		/* Wait for the command to complete */
+		wait_for_ctrl_irq (ctrl);
+
+		rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+		if (rc) {
+			err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+			/* Done with exclusive hardware access */
+			up(&amp;ctrl-&gt;crit_sect);
+			return rc;  
+		}
+
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+
+		return(rc);
+	}
+	return 0;
+}
+
+
+/**
+ * remove_board - Turns off slot and LED's
+ *
+ */
+static u32 remove_board(struct pci_func *func, struct controller *ctrl)
+{
+	int index;
+	u8 skip = 0;
+	u8 device;
+	u8 hp_slot;
+	u32 rc;
+	struct resource_lists res_lists;
+	struct pci_func *temp_func;
+	struct slot *p_slot;
+
+	if (func == NULL)
+		return(1);
+
+	if (shpchp_unconfigure_device(func))
+		return(1);
+
+	device = func-&gt;device;
+
+	hp_slot = func-&gt;device - ctrl-&gt;slot_device_offset;
+	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
+
+	if ((ctrl-&gt;add_support) &amp;&amp;
+		!(func-&gt;bus_head || func-&gt;mem_head || func-&gt;p_mem_head || func-&gt;io_head)) {
+		/* Here we check to see if we've saved any of the board's
+		 * resources already.  If so, we'll skip the attempt to
+		 * determine what's being used.
+		 */
+		index = 0;
+
+		temp_func = func;
+
+		while ((temp_func = shpchp_slot_find(temp_func-&gt;bus, temp_func-&gt;device, index++))) {
+			if (temp_func-&gt;bus_head || temp_func-&gt;mem_head
+			    || temp_func-&gt;p_mem_head || temp_func-&gt;io_head) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip)
+			rc = shpchp_save_used_resources(ctrl, func, DISABLE_CARD);
+	}
+	/* Change status to shutdown */
+	if (func-&gt;is_a_board)
+		func-&gt;status = 0x01;
+	func-&gt;configured = 0;
+
+	/* Wait for exclusive access to hardware */
+	down(&amp;ctrl-&gt;crit_sect);
+
+	/* turn off slot, turn on Amber LED, turn off Green LED */
+	rc = p_slot-&gt;hpc_ops-&gt;slot_disable(p_slot);
+	if (rc) {
+		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	rc = p_slot-&gt;hpc_ops-&gt;check_cmd_status(ctrl);
+	if (rc) {
+		err("%s: Failed to disable slot, error code(%d)\n", __FUNCTION__, rc);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return rc;  
+	}
+	
+	rc = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+	if (rc) {
+		err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
+		/* Done with exclusive hardware access */
+		up(&amp;ctrl-&gt;crit_sect);
+		return rc;
+	}
+	/* Wait for the command to complete */
+	wait_for_ctrl_irq (ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&amp;ctrl-&gt;crit_sect);
+
+	if (ctrl-&gt;add_support) {
+		while (func) {
+			res_lists.io_head = ctrl-&gt;io_head;
+			res_lists.mem_head = ctrl-&gt;mem_head;
+			res_lists.p_mem_head = ctrl-&gt;p_mem_head;
+			res_lists.bus_head = ctrl-&gt;bus_head;
+
+			dbg("Returning resources to ctlr lists for (B/D/F) = (%#x/%#x/%#x)\n", func-&gt;bus, 
+				func-&gt;device, func-&gt;function);
+
+			shpchp_return_board_resources(func, &amp;res_lists);
+
+			ctrl-&gt;io_head = res_lists.io_head;
+			ctrl-&gt;mem_head = res_lists.mem_head;
+			ctrl-&gt;p_mem_head = res_lists.p_mem_head;
+			ctrl-&gt;bus_head = res_lists.bus_head;
+
+			shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;mem_head));
+			shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;p_mem_head));
+			shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;io_head));
+			shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;bus_head));
+
+			if (is_bridge(func)) {
+				dbg("PCI Bridge Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl-&gt;seg, func-&gt;bus, 
+					func-&gt;device, func-&gt;function);
+				bridge_slot_remove(func);
+			} else
+				dbg("PCI Function Hot-Remove s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl-&gt;seg, func-&gt;bus, 
+					func-&gt;device, func-&gt;function);
+				slot_remove(func);
+
+			func = shpchp_slot_find(ctrl-&gt;slot_bus, device, 0);
+		}
+
+		/* Setup slot structure with entry for empty slot */
+		func = shpchp_slot_create(ctrl-&gt;slot_bus);
+
+		if (func == NULL) {
+			return(1);
+		}
+
+		func-&gt;bus = ctrl-&gt;slot_bus;
+		func-&gt;device = device;
+		func-&gt;function = 0;
+		func-&gt;configured = 0;
+		func-&gt;switch_save = 0x10;
+		func-&gt;is_a_board = 0;
+	}
+
+	return 0;
+}
+
+
+static void pushbutton_helper_thread (unsigned long data)
+{
+	pushbutton_pending = data;
+
+	up(&amp;event_semaphore);
+}
+
+
+/* this is the main worker thread */
+static int event_thread(void* data)
+{
+	struct controller *ctrl;
+	lock_kernel();
+	daemonize("shpchpd_event");
+	unlock_kernel();
+
+	while (1) {
+		dbg("!!!!event_thread sleeping\n");
+		down_interruptible (&amp;event_semaphore);
+		dbg("event_thread woken finished = %d\n", event_finished);
+		if (event_finished || signal_pending(current))
+			break;
+		/* Do stuff here */
+		if (pushbutton_pending)
+			shpchp_pushbutton_thread(pushbutton_pending);
+		else
+			for (ctrl = shpchp_ctrl_list; ctrl; ctrl=ctrl-&gt;next)
+				interrupt_event_handler(ctrl);
+	}
+	dbg("event_thread signals exit\n");
+	up(&amp;event_exit);
+	return 0;
+}
+
+int shpchp_event_start_thread (void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX_LOCKED(&amp;event_exit);
+	event_finished=0;
+
+	init_MUTEX_LOCKED(&amp;event_semaphore);
+	pid = kernel_thread(event_thread, 0, 0);
+
+	if (pid &lt; 0) {
+		err ("Can't start up our event thread\n");
+		return -1;
+	}
+	dbg("Our event thread pid = %d\n", pid);
+	return 0;
+}
+
+
+void shpchp_event_stop_thread (void)
+{
+	event_finished = 1;
+	dbg("event_thread finish command given\n");
+	up(&amp;event_semaphore);
+	dbg("wait for event_thread to exit\n");
+	down(&amp;event_exit);
+}
+
+
+static int update_slot_info (struct slot *slot)
+{
+	struct hotplug_slot_info *info;
+	int result;
+
+	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	slot-&gt;hpc_ops-&gt;get_power_status(slot, &amp;(info-&gt;power_status));
+	slot-&gt;hpc_ops-&gt;get_attention_status(slot, &amp;(info-&gt;attention_status));
+	slot-&gt;hpc_ops-&gt;get_latch_status(slot, &amp;(info-&gt;latch_status));
+	slot-&gt;hpc_ops-&gt;get_adapter_status(slot, &amp;(info-&gt;adapter_status));
+
+	result = pci_hp_change_slot_info(slot-&gt;hotplug_slot, info);
+	kfree (info);
+	return result;
+}
+
+static void interrupt_event_handler(struct controller *ctrl)
+{
+	int loop = 0;
+	int change = 1;
+	struct pci_func *func;
+	u8 hp_slot;
+	u8 getstatus;
+	struct slot *p_slot;
+
+	dbg("%s:\n", __FUNCTION__);
+	while (change) {
+		change = 0;
+
+		for (loop = 0; loop &lt; 10; loop++) {
+			if (ctrl-&gt;event_queue[loop].event_type != 0) {
+				dbg("%s:loop %x event_type %x\n", __FUNCTION__, loop, 
+					ctrl-&gt;event_queue[loop].event_type);
+				hp_slot = ctrl-&gt;event_queue[loop].hp_slot;
+
+				func = shpchp_slot_find(ctrl-&gt;slot_bus, (hp_slot + ctrl-&gt;slot_device_offset), 0);
+
+				p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl-&gt;slot_device_offset);
+
+				dbg("%s: hp_slot %d, func %p, p_slot %p\n", __FUNCTION__, hp_slot, func, p_slot);
+
+				if (ctrl-&gt;event_queue[loop].event_type == INT_BUTTON_CANCEL) {
+					dbg("%s: button cancel\n", __FUNCTION__);
+					del_timer(&amp;p_slot-&gt;task_event);
+
+					switch (p_slot-&gt;state) {
+					case BLINKINGOFF_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&amp;ctrl-&gt;crit_sect);
+
+						p_slot-&gt;hpc_ops-&gt;green_led_on(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);
+						break;
+					case BLINKINGON_STATE:
+						/* Wait for exclusive access to hardware */
+						down(&amp;ctrl-&gt;crit_sect);
+
+						p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+						/* Wait for the command to complete */
+						wait_for_ctrl_irq (ctrl);
+
+						/* Done with exclusive hardware access */
+						up(&amp;ctrl-&gt;crit_sect);
+
+						break;
+					default:
+						warn("Not a valid state\n");
+						return;
+					}
+					info(msg_button_cancel, p_slot-&gt;number);
+					p_slot-&gt;state = STATIC_STATE;
+				} else if (ctrl-&gt;event_queue[loop].event_type == INT_BUTTON_PRESS) {
+					/* Button Pressed (No action on 1st press...) */
+					dbg("%s: Button pressed\n", __FUNCTION__);
+
+					p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+					if (getstatus) {
+						/* slot is on */
+						dbg("%s: slot is on\n", __FUNCTION__);
+						p_slot-&gt;state = BLINKINGOFF_STATE;
+						info(msg_button_off, p_slot-&gt;number);
+					} else {
+						/* slot is off */
+						dbg("%s: slot is off\n", __FUNCTION__);
+						p_slot-&gt;state = BLINKINGON_STATE;
+						info(msg_button_on, p_slot-&gt;number);
+					}
+
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					/* blink green LED and turn off amber */
+					p_slot-&gt;hpc_ops-&gt;green_led_blink(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+					
+					p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 0);
+
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+
+					init_timer(&amp;p_slot-&gt;task_event);
+					p_slot-&gt;task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
+					p_slot-&gt;task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
+					p_slot-&gt;task_event.data = (unsigned long) p_slot;
+
+					dbg("%s: add_timer p_slot = %p\n", __FUNCTION__,(void *) p_slot);
+					add_timer(&amp;p_slot-&gt;task_event);
+				} else if (ctrl-&gt;event_queue[loop].event_type == INT_POWER_FAULT) {
+					/***********POWER FAULT********************/
+					dbg("%s: power fault\n", __FUNCTION__);
+					/* Wait for exclusive access to hardware */
+					down(&amp;ctrl-&gt;crit_sect);
+
+					p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+					
+					p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+					/* Wait for the command to complete */
+					wait_for_ctrl_irq (ctrl);
+
+					/* Done with exclusive hardware access */
+					up(&amp;ctrl-&gt;crit_sect);
+				} else {
+					/* refresh notification */
+					if (p_slot)
+						update_slot_info(p_slot);
+				}
+
+				ctrl-&gt;event_queue[loop].event_type = 0;
+
+				change = 1;
+			}
+		}		/* End of FOR loop */
+	}
+
+	return;
+}
+
+
+/**
+ * shpchp_pushbutton_thread
+ *
+ * Scheduled procedure to handle blocking stuff for the pushbuttons
+ * Handles all pending events and exits.
+ *
+ */
+void shpchp_pushbutton_thread (unsigned long slot)
+{
+	struct slot *p_slot = (struct slot *) slot;
+	u8 getstatus;
+	int rc;
+	
+	pushbutton_pending = 0;
+
+	if (!p_slot) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return;
+	}
+
+	p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+	if (getstatus) {
+		p_slot-&gt;state = POWEROFF_STATE;
+		dbg("In power_down_board, b:d(%x:%x)\n", p_slot-&gt;bus, p_slot-&gt;device);
+
+		if (shpchp_disable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+			/* Turn on the Attention LED */
+			rc = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+	
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot-&gt;ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		}
+		p_slot-&gt;state = STATIC_STATE;
+	} else {
+		p_slot-&gt;state = POWERON_STATE;
+		dbg("In add_board, b:d(%x:%x)\n", p_slot-&gt;bus, p_slot-&gt;device);
+
+		if (shpchp_enable_slot(p_slot)) {
+			/* Wait for exclusive access to hardware */
+			down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+			/* Turn off the green LED */
+			rc = p_slot-&gt;hpc_ops-&gt;set_attention_status(p_slot, 1);
+			if (rc) {
+				err("%s: Issue of Set Atten Indicator On command failed\n", __FUNCTION__);
+				return;
+			}
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot-&gt;ctrl);
+			
+			p_slot-&gt;hpc_ops-&gt;green_led_off(p_slot);
+
+			/* Wait for the command to complete */
+			wait_for_ctrl_irq (p_slot-&gt;ctrl);
+
+			/* Done with exclusive hardware access */
+			up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		}
+		p_slot-&gt;state = STATIC_STATE;
+	}
+
+	return;
+}
+
+
+int shpchp_enable_slot (struct slot *p_slot)
+{
+	u8 getstatus = 0;
+	int rc;
+	struct pci_func *func;
+
+	func = shpchp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, 0);
+	if (!func) {
+		dbg("%s: Error! slot NULL\n", __FUNCTION__);
+		return (1);
+	}
+
+	/* Check to see if (latch closed, card present, power off) */
+	down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+	rc = p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;getstatus);
+	if (rc || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	rc = p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	if (rc || !getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	rc = p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+	if (rc || getstatus) {
+		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+	slot_remove(func);
+
+	func = shpchp_slot_create(p_slot-&gt;bus);
+	if (func == NULL)
+		return (1);
+
+	func-&gt;bus = p_slot-&gt;bus;
+	func-&gt;device = p_slot-&gt;device;
+	func-&gt;function = 0;
+	func-&gt;configured = 0;
+	func-&gt;is_a_board = 1;
+
+	/* We have to save the presence info for these slots */
+	p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+	p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	func-&gt;switch_save = !getstatus? 0x10:0;
+
+	rc = board_added(func, p_slot-&gt;ctrl);
+	if (rc) {
+		if (is_bridge(func))
+			bridge_slot_remove(func);
+		else
+			slot_remove(func);
+
+		/* Setup slot structure with entry for empty slot */
+		func = shpchp_slot_create(p_slot-&gt;bus);
+		if (func == NULL)
+			return (1);	/* Out of memory */
+
+		func-&gt;bus = p_slot-&gt;bus;
+		func-&gt;device = p_slot-&gt;device;
+		func-&gt;function = 0;
+		func-&gt;configured = 0;
+		func-&gt;is_a_board = 1;
+
+		/* We have to save the presence info for these slots */
+		p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;(func-&gt;presence_save));
+		p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+		func-&gt;switch_save = !getstatus? 0x10:0;
+	}
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return rc;
+}
+
+
+int shpchp_disable_slot (struct slot *p_slot)
+{
+	u8 class_code, header_type, BCR;
+	u8 index = 0;
+	u8 getstatus = 0;
+	u32 rc = 0;
+	int ret = 0;
+	unsigned int devfn;
+	struct pci_bus *pci_bus = p_slot-&gt;ctrl-&gt;pci_dev-&gt;subordinate;
+	struct pci_func *func;
+
+	if (!p_slot-&gt;ctrl)
+		return (1);
+
+	/* Check to see if (latch closed, card present, power on) */
+	down(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+	ret = p_slot-&gt;hpc_ops-&gt;get_adapter_status(p_slot, &amp;getstatus);
+	if (ret || !getstatus) {
+		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	ret = p_slot-&gt;hpc_ops-&gt;get_latch_status(p_slot, &amp;getstatus);
+	if (ret || !getstatus) {
+		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	ret = p_slot-&gt;hpc_ops-&gt;get_power_status(p_slot, &amp;getstatus);
+	if (ret || !getstatus) {
+		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot-&gt;number);
+		up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+		return (0);
+	}
+	up(&amp;p_slot-&gt;ctrl-&gt;crit_sect);
+
+	func = shpchp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, index++);
+
+	/* Make sure there are no video controllers here
+	 * for all func of p_slot
+	 */
+	while (func &amp;&amp; !rc) {
+		pci_bus-&gt;number = func-&gt;bus;
+		devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+		/* Check the Class Code */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &amp;class_code);
+		if (rc)
+			return rc;
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY) {
+			/* Display/Video adapter (not supported) */
+			rc = REMOVE_NOT_SUPPORTED;
+		} else {
+			/* See if it's a bridge */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &amp;header_type);
+			if (rc)
+				return rc;
+
+			/* If it's a bridge, check the VGA Enable bit */
+			if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+				rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;BCR);
+				if (rc)
+					return rc;
+
+				/* If the VGA Enable bit is set, remove isn't supported */
+				if (BCR &amp; PCI_BRIDGE_CTL_VGA) {
+					rc = REMOVE_NOT_SUPPORTED;
+				}
+			}
+		}
+
+		func = shpchp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, index++);
+	}
+
+	func = shpchp_slot_find(p_slot-&gt;bus, p_slot-&gt;device, 0);
+	if ((func != NULL) &amp;&amp; !rc) {
+		rc = remove_board(func, p_slot-&gt;ctrl);
+	} else if (!rc)
+		rc = 1;
+
+	if (p_slot)
+		update_slot_info(p_slot);
+
+	return(rc);
+}
+
+
+/**
+ * configure_new_device - Configures the PCI header information of one board.
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Returns 0 if success
+ *
+ */
+static u32 configure_new_device (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists * resources, u8 bridge_bus, u8 bridge_dev)
+{
+	u8 temp_byte, function, max_functions, stop_it;
+	int rc;
+	u32 ID;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	int index;
+
+	new_slot = func;
+
+	dbg("%s\n", __FUNCTION__);
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+
+	/* Check for Multi-function device */
+	rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(func-&gt;device, func-&gt;function), 0x0E, &amp;temp_byte);
+	if (rc) {
+		dbg("%s: rc = %d\n", __FUNCTION__, rc);
+		return rc;
+	}
+
+	if (temp_byte &amp; 0x80)	/* Multi-function device */
+		max_functions = 8;
+	else
+		max_functions = 1;
+
+	function = 0;
+
+	do {
+		rc = configure_new_function(ctrl, new_slot, behind_bridge, resources, bridge_bus, bridge_dev);
+
+		if (rc) {
+			dbg("configure_new_function failed %d\n",rc);
+			index = 0;
+
+			while (new_slot) {
+				new_slot = shpchp_slot_find(new_slot-&gt;bus, new_slot-&gt;device, index++);
+
+				if (new_slot)
+					shpchp_return_board_resources(new_slot, resources);
+			}
+
+			return(rc);
+		}
+
+		function++;
+
+		stop_it = 0;
+
+		/*  The following loop skips to the next present function
+		 *  and creates a board structure
+		 */
+
+		while ((function &lt; max_functions) &amp;&amp; (!stop_it)) {
+			pci_bus_read_config_dword(pci_bus, PCI_DEVFN(func-&gt;device, function), 0x00, &amp;ID);
+
+			if (ID == 0xFFFFFFFF) {	  /* There's nothing there. */
+				function++;
+			} else {  /* There's something there */
+				/* Setup slot structure. */
+				new_slot = shpchp_slot_create(func-&gt;bus);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					return(1);
+				}
+
+				new_slot-&gt;bus = func-&gt;bus;
+				new_slot-&gt;device = func-&gt;device;
+				new_slot-&gt;function = function;
+				new_slot-&gt;is_a_board = 1;
+				new_slot-&gt;status = 0;
+
+				stop_it++;
+			}
+		}
+
+	} while (function &lt; max_functions);
+	dbg("returning from configure_new_device\n");
+
+	return 0;
+}
+
+
+/*
+ * Configuration logic that involves the hotplug data structures and 
+ * their bookkeeping
+ */
+
+
+/**
+ * configure_new_function - Configures the PCI header information of one device
+ *
+ * @ctrl: pointer to controller structure
+ * @func: pointer to function structure
+ * @behind_bridge: 1 if this is a recursive call, 0 if not
+ * @resources: pointer to set of resource lists
+ *
+ * Calls itself recursively for bridged devices.
+ * Returns 0 if success
+ *
+ */
+static int configure_new_function (struct controller * ctrl, struct pci_func * func,
+	u8 behind_bridge, struct resource_lists *resources, u8 bridge_bus, u8 bridge_dev)
+{
+	int cloop;
+	u8 temp_byte;
+	u8 device;
+	u8 class_code;
+	u16 temp_word;
+	u32 rc;
+	u32 temp_register;
+	u32 base;
+	u32 ID;
+	unsigned int devfn;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_resource *hold_mem_node;
+	struct pci_resource *hold_p_mem_node;
+	struct pci_resource *hold_IO_node;
+	struct pci_resource *hold_bus_node;
+	struct irq_mapping irqs;
+	struct pci_func *new_slot;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct resource_lists temp_resources;
+#if defined(CONFIG_X86_64)
+	u8 IRQ=0;
+#endif
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	/* Check for Bridge */
+	rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &amp;temp_byte);
+	if (rc)
+		return rc;
+
+	if ((temp_byte &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) { /* PCI-PCI Bridge */
+		/* set Primary bus */
+		dbg("set Primary bus = 0x%x\n", func-&gt;bus);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_PRIMARY_BUS, func-&gt;bus);
+		if (rc)
+			return rc;
+
+		/* find range of busses to use */
+		bus_node = get_max_resource(&amp;resources-&gt;bus_head, 1L);
+
+		/* If we don't have any busses to allocate, we can't continue */
+		if (!bus_node) {
+			err("Got NO bus resource to use\n");
+			return -ENOMEM;
+		}
+		dbg("Got ranges of buses to use: base:len=0x%x:%x\n", bus_node-&gt;base, bus_node-&gt;length);
+
+		/* set Secondary bus */
+		temp_byte = (u8)bus_node-&gt;base;
+		dbg("set Secondary bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* set subordinate bus */
+		temp_byte = (u8)(bus_node-&gt;base + bus_node-&gt;length - 1);
+		dbg("set subordinate bus = 0x%x\n", temp_byte);
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+		if (rc)
+			return rc;
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+		if (rc)
+			return rc;
+
+		/* Setup the IO, memory, and prefetchable windows */
+
+		io_node = get_max_resource(&amp;(resources-&gt;io_head), 0x1000L);
+		if (io_node) {
+			dbg("io_node(base, len, next) (%x, %x, %p)\n", io_node-&gt;base, io_node-&gt;length, io_node-&gt;next);
+		}
+
+		mem_node = get_max_resource(&amp;(resources-&gt;mem_head), 0x100000L);
+		if (mem_node) {
+			dbg("mem_node(base, len, next) (%x, %x, %p)\n", mem_node-&gt;base, mem_node-&gt;length, mem_node-&gt;next);
+		}
+
+		if (resources-&gt;p_mem_head)
+			p_mem_node = get_max_resource(&amp;(resources-&gt;p_mem_head), 0x100000L);
+		else {
+			/*
+			 * In some platform implementation, MEM and PMEM are not
+			 *  distinguished, and hence ACPI _CRS has only MEM entries
+			 *  for both MEM and PMEM.
+			 */
+			dbg("using MEM for PMEM\n");
+			p_mem_node = get_max_resource(&amp;(resources-&gt;mem_head), 0x100000L);
+		}
+		if (p_mem_node) {
+			dbg("p_mem_node(base, len, next) (%x, %x, %p)\n", p_mem_node-&gt;base, p_mem_node-&gt;length, p_mem_node-&gt;next);
+		}
+
+		/* set up the IRQ info */
+		if (!resources-&gt;irqs) {
+			irqs.barber_pole = 0;
+			irqs.interrupt[0] = 0;
+			irqs.interrupt[1] = 0;
+			irqs.interrupt[2] = 0;
+			irqs.interrupt[3] = 0;
+			irqs.valid_INT = 0;
+		} else {
+			irqs.barber_pole = resources-&gt;irqs-&gt;barber_pole;
+			irqs.interrupt[0] = resources-&gt;irqs-&gt;interrupt[0];
+			irqs.interrupt[1] = resources-&gt;irqs-&gt;interrupt[1];
+			irqs.interrupt[2] = resources-&gt;irqs-&gt;interrupt[2];
+			irqs.interrupt[3] = resources-&gt;irqs-&gt;interrupt[3];
+			irqs.valid_INT = resources-&gt;irqs-&gt;valid_INT;
+		}
+
+		/* set up resource lists that are now aligned on top and bottom
+		 * for anything behind the bridge.
+		 */
+		temp_resources.bus_head = bus_node;
+		temp_resources.io_head = io_node;
+		temp_resources.mem_head = mem_node;
+		temp_resources.p_mem_head = p_mem_node;
+		temp_resources.irqs = &amp;irqs;
+
+		/* Make copies of the nodes we are going to pass down so that
+		 * if there is a problem,we can just use these to free resources
+		 */
+		hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+
+		if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) {
+			if (hold_bus_node)
+				kfree(hold_bus_node);
+			if (hold_IO_node)
+				kfree(hold_IO_node);
+			if (hold_mem_node)
+				kfree(hold_mem_node);
+			if (hold_p_mem_node)
+				kfree(hold_p_mem_node);
+
+			return(1);
+		}
+
+		memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource));
+
+		bus_node-&gt;base += 1;
+		bus_node-&gt;length -= 1;
+		bus_node-&gt;next = NULL;
+
+		/* If we have IO resources copy them and fill in the bridge's
+		 * IO range registers
+		 */
+		if (io_node) {
+			memcpy(hold_IO_node, io_node, sizeof(struct pci_resource));
+			io_node-&gt;next = NULL;
+
+			/* set IO base and Limit registers */
+			RES_CHECK(io_node-&gt;base, 8);
+			temp_byte = (u8)(io_node-&gt;base &gt;&gt; 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+			RES_CHECK(io_node-&gt;base + io_node-&gt;length - 1, 8);
+			temp_byte = (u8)((io_node-&gt;base + io_node-&gt;length - 1) &gt;&gt; 8);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+		} else {
+			kfree(hold_IO_node);
+			hold_IO_node = NULL;
+		}
+
+		/* If we have memory resources copy them and fill in the bridge's
+		 * memory range registers.  Otherwise, fill in the range
+		 * registers with values that disable them.
+		 */
+		if (mem_node) {
+			memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource));
+			mem_node-&gt;next = NULL;
+
+			/* set Mem base and Limit registers */
+			RES_CHECK(mem_node-&gt;base, 16);
+			temp_word = (u32)(mem_node-&gt;base &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			RES_CHECK(mem_node-&gt;base + mem_node-&gt;length - 1, 16);
+			temp_word = (u32)((mem_node-&gt;base + mem_node-&gt;length - 1) &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_mem_node);
+			hold_mem_node = NULL;
+		}
+
+		/* If we have prefetchable memory resources copy them and 
+		 * fill in the bridge's memory range registers.  Otherwise,
+		 * fill in the range registers with values that disable them.
+		 */
+		if (p_mem_node) {
+			memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource));
+			p_mem_node-&gt;next = NULL;
+
+			/* set Pre Mem base and Limit registers */
+			RES_CHECK(p_mem_node-&gt;base, 16);
+			temp_word = (u32)(p_mem_node-&gt;base &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			RES_CHECK(p_mem_node-&gt;base + p_mem_node-&gt;length - 1, 16);
+			temp_word = (u32)((p_mem_node-&gt;base + p_mem_node-&gt;length - 1) &gt;&gt; 16);
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+		} else {
+			temp_word = 0xFFFF;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+			temp_word = 0x0000;
+			rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+			kfree(hold_p_mem_node);
+			hold_p_mem_node = NULL;
+		}
+
+		/* Adjust this to compensate for extra adjustment in first loop */
+		irqs.barber_pole--;
+
+		rc = 0;
+
+		/* Here we actually find the devices and configure them */
+		for (device = 0; (device &lt;= 0x1F) &amp;&amp; !rc; device++) {
+			irqs.barber_pole = (irqs.barber_pole + 1) &amp; 0x03;
+
+			ID = 0xFFFFFFFF;
+			pci_bus-&gt;number = hold_bus_node-&gt;base;
+			pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &amp;ID);
+			pci_bus-&gt;number = func-&gt;bus;
+
+			if (ID != 0xFFFFFFFF) {	  /*  device Present */
+				/* Setup slot structure. */
+				new_slot = shpchp_slot_create(hold_bus_node-&gt;base);
+
+				if (new_slot == NULL) {
+					/* Out of memory */
+					rc = -ENOMEM;
+					continue;
+				}
+
+				new_slot-&gt;bus = hold_bus_node-&gt;base;
+				new_slot-&gt;device = device;
+				new_slot-&gt;function = 0;
+				new_slot-&gt;is_a_board = 1;
+				new_slot-&gt;status = 0;
+
+				rc = configure_new_device(ctrl, new_slot, 1, &amp;temp_resources, func-&gt;bus, func-&gt;device);
+				dbg("configure_new_device rc=0x%x\n",rc);
+			}	/* End of IF (device in slot?) */
+		}		/* End of FOR loop */
+
+		if (rc) {
+			shpchp_destroy_resource_list(&amp;temp_resources);
+
+			return_resource(&amp;(resources-&gt;bus_head), hold_bus_node);
+			return_resource(&amp;(resources-&gt;io_head), hold_IO_node);
+			return_resource(&amp;(resources-&gt;mem_head), hold_mem_node);
+			return_resource(&amp;(resources-&gt;p_mem_head), hold_p_mem_node);
+			return(rc);
+		}
+
+		/* save the interrupt routing information */
+		if (resources-&gt;irqs) {
+			resources-&gt;irqs-&gt;interrupt[0] = irqs.interrupt[0];
+			resources-&gt;irqs-&gt;interrupt[1] = irqs.interrupt[1];
+			resources-&gt;irqs-&gt;interrupt[2] = irqs.interrupt[2];
+			resources-&gt;irqs-&gt;interrupt[3] = irqs.interrupt[3];
+			resources-&gt;irqs-&gt;valid_INT = irqs.valid_INT;
+		} else if (!behind_bridge) {
+			/* We need to hook up the interrupts here */
+			for (cloop = 0; cloop &lt; 4; cloop++) {
+				if (irqs.valid_INT &amp; (0x01 &lt;&lt; cloop)) {
+					rc = shpchp_set_irq(func-&gt;bus, func-&gt;device,
+							   0x0A + cloop, irqs.interrupt[cloop]);
+					if (rc) {
+						shpchp_destroy_resource_list (&amp;temp_resources);
+						return_resource(&amp;(resources-&gt;bus_head), hold_bus_node);
+						return_resource(&amp;(resources-&gt;io_head), hold_IO_node);
+						return_resource(&amp;(resources-&gt;mem_head), hold_mem_node);
+						return_resource(&amp;(resources-&gt;p_mem_head), hold_p_mem_node);
+						return rc;
+					}
+				}
+			}	/* end of for loop */
+		}
+
+		/* Return unused bus resources
+		 * First use the temporary node to store information for the board
+		 */
+		if (hold_bus_node &amp;&amp; bus_node &amp;&amp; temp_resources.bus_head) {
+			hold_bus_node-&gt;length = bus_node-&gt;base - hold_bus_node-&gt;base;
+
+			hold_bus_node-&gt;next = func-&gt;bus_head;
+			func-&gt;bus_head = hold_bus_node;
+
+			temp_byte = (u8)(temp_resources.bus_head-&gt;base - 1);
+
+			/* set subordinate bus */
+			dbg("re-set subordinate bus = 0x%x\n", temp_byte);
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte);
+
+			if (temp_resources.bus_head-&gt;length == 0) {
+				kfree(temp_resources.bus_head);
+				temp_resources.bus_head = NULL;
+			} else {
+				dbg("return bus res of b:d(0x%x:%x) base:len(0x%x:%x)\n",
+					func-&gt;bus, func-&gt;device, temp_resources.bus_head-&gt;base, temp_resources.bus_head-&gt;length);
+				return_resource(&amp;(resources-&gt;bus_head), temp_resources.bus_head);
+			}
+		}
+
+		/* If we have IO space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_IO_node &amp;&amp; temp_resources.io_head) {
+			io_node = do_pre_bridge_resource_split(&amp;(temp_resources.io_head),
+							       &amp;hold_IO_node, 0x1000);
+
+			/* Check if we were able to split something off */
+			if (io_node) {
+				hold_IO_node-&gt;base = io_node-&gt;base + io_node-&gt;length;
+
+				RES_CHECK(hold_IO_node-&gt;base, 8);
+				temp_byte = (u8)((hold_IO_node-&gt;base) &gt;&gt; 8);
+				rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte);
+
+				return_resource(&amp;(resources-&gt;io_head), io_node);
+			}
+
+			io_node = do_bridge_resource_split(&amp;(temp_resources.io_head), 0x1000);
+
+			/*  Check if we were able to split something off */
+			if (io_node) {
+				/* First use the temporary node to store information for the board */
+				hold_IO_node-&gt;length = io_node-&gt;base - hold_IO_node-&gt;base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_IO_node-&gt;length) {
+					hold_IO_node-&gt;next = func-&gt;io_head;
+					func-&gt;io_head = hold_IO_node;
+
+					RES_CHECK(io_node-&gt;base - 1, 8);
+					temp_byte = (u8)((io_node-&gt;base - 1) &gt;&gt; 8);
+					rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&amp;(resources-&gt;io_head), io_node);
+				} else {
+					/* it doesn't need any IO */
+					temp_byte = 0x00;
+					rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte);
+
+					return_resource(&amp;(resources-&gt;io_head), io_node);
+					kfree(hold_IO_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_IO_node-&gt;next = func-&gt;io_head;
+				func-&gt;io_head = hold_IO_node;
+			}
+		} else if (hold_IO_node) {
+			/* it used the whole range */
+			hold_IO_node-&gt;next = func-&gt;io_head;
+			func-&gt;io_head = hold_IO_node;
+		}
+
+		/* If we have memory space available and there is some left,
+		 * return the unused portion
+		 */
+		if (hold_mem_node &amp;&amp; temp_resources.mem_head) {
+			mem_node = do_pre_bridge_resource_split(&amp;(temp_resources.mem_head), &amp;hold_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				hold_mem_node-&gt;base = mem_node-&gt;base + mem_node-&gt;length;
+
+				RES_CHECK(hold_mem_node-&gt;base, 16);
+				temp_word = (u32)((hold_mem_node-&gt;base) &gt;&gt; 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word);
+
+				return_resource(&amp;(resources-&gt;mem_head), mem_node);
+			}
+
+			mem_node = do_bridge_resource_split(&amp;(temp_resources.mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_mem_node-&gt;length = mem_node-&gt;base - hold_mem_node-&gt;base;
+
+				if (hold_mem_node-&gt;length) {
+					hold_mem_node-&gt;next = func-&gt;mem_head;
+					func-&gt;mem_head = hold_mem_node;
+
+					/* configure end address */
+					RES_CHECK(mem_node-&gt;base - 1, 16);
+					temp_word = (u32)((mem_node-&gt;base - 1) &gt;&gt; 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					/* Return unused resources to the pool */
+					return_resource(&amp;(resources-&gt;mem_head), mem_node);
+				} else {
+					/* it doesn't need any Mem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word);
+
+					return_resource(&amp;(resources-&gt;mem_head), mem_node);
+					kfree(hold_mem_node);
+				}
+			} else {
+				/* it used most of the range */
+				hold_mem_node-&gt;next = func-&gt;mem_head;
+				func-&gt;mem_head = hold_mem_node;
+			}
+		} else if (hold_mem_node) {
+			/* it used the whole range */
+			hold_mem_node-&gt;next = func-&gt;mem_head;
+			func-&gt;mem_head = hold_mem_node;
+		}
+
+		/* If we have prefetchable memory space available and there is some 
+		 * left at the end, return the unused portion
+		 */
+		if (hold_p_mem_node &amp;&amp; temp_resources.p_mem_head) {
+			p_mem_node = do_pre_bridge_resource_split(&amp;(temp_resources.p_mem_head),
+								  &amp;hold_p_mem_node, 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				hold_p_mem_node-&gt;base = p_mem_node-&gt;base + p_mem_node-&gt;length;
+
+				RES_CHECK(hold_p_mem_node-&gt;base, 16);
+				temp_word = (u32)((hold_p_mem_node-&gt;base) &gt;&gt; 16);
+				rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word);
+
+				return_resource(&amp;(resources-&gt;p_mem_head), p_mem_node);
+			}
+
+			p_mem_node = do_bridge_resource_split(&amp;(temp_resources.p_mem_head), 0x100000L);
+
+			/* Check if we were able to split something off */
+			if (p_mem_node) {
+				/* First use the temporary node to store information for the board */
+				hold_p_mem_node-&gt;length = p_mem_node-&gt;base - hold_p_mem_node-&gt;base;
+
+				/* If we used any, add it to the board's list */
+				if (hold_p_mem_node-&gt;length) {
+					hold_p_mem_node-&gt;next = func-&gt;p_mem_head;
+					func-&gt;p_mem_head = hold_p_mem_node;
+
+					RES_CHECK(p_mem_node-&gt;base - 1, 16);
+					temp_word = (u32)((p_mem_node-&gt;base - 1) &gt;&gt; 16);
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&amp;(resources-&gt;p_mem_head), p_mem_node);
+				} else {
+					/* it doesn't need any PMem */
+					temp_word = 0x0000;
+					rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word);
+
+					return_resource(&amp;(resources-&gt;p_mem_head), p_mem_node);
+					kfree(hold_p_mem_node);
+				}
+			} else {
+				/* it used the most of the range */
+				hold_p_mem_node-&gt;next = func-&gt;p_mem_head;
+				func-&gt;p_mem_head = hold_p_mem_node;
+			}
+		} else if (hold_p_mem_node) {
+			/* it used the whole range */
+			hold_p_mem_node-&gt;next = func-&gt;p_mem_head;
+			func-&gt;p_mem_head = hold_p_mem_node;
+		}
+
+		/* We should be configuring an IRQ and the bridge's base address
+		 * registers if it needs them.  Although we have never seen such
+		 * a device
+		 */
+
+		shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_BRIDGE);
+
+		dbg("PCI Bridge Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl-&gt;seg, func-&gt;bus, func-&gt;device, func-&gt;function);
+	} else if ((temp_byte &amp; 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+		/* Standard device */
+		u64	base64;
+		rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &amp;class_code);
+
+		if (class_code == PCI_BASE_CLASS_DISPLAY)
+			return (DEVICE_TYPE_NOT_SUPPORTED);
+
+		/* Figure out IO and memory needs */
+		for (cloop = PCI_BASE_ADDRESS_0; cloop &lt;= PCI_BASE_ADDRESS_5; cloop += 4) {
+			temp_register = 0xFFFFFFFF;
+
+			rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+			rc = pci_bus_read_config_dword(pci_bus, devfn, cloop, &amp;temp_register);
+			dbg("Bar[%x]=0x%x on bus:dev:func(0x%x:%x:%x)\n", cloop, temp_register, func-&gt;bus, func-&gt;device, 
+				func-&gt;function);
+
+			if (!temp_register)
+				continue;
+
+			base64 = 0L;
+			if (temp_register &amp; PCI_BASE_ADDRESS_SPACE_IO) {
+				/* Map IO */
+
+				/* set base = amount of IO space */
+				base = temp_register &amp; 0xFFFFFFFC;
+				base = ~base + 1;
+
+				dbg("NEED IO length(0x%x)\n", base);
+				io_node = get_io_resource(&amp;(resources-&gt;io_head),(ulong)base);
+
+				/* allocate the resource to the board */
+				if (io_node) {
+					dbg("Got IO base=0x%x(length=0x%x)\n", io_node-&gt;base, io_node-&gt;length);
+					base = (u32)io_node-&gt;base;
+					io_node-&gt;next = func-&gt;io_head;
+					func-&gt;io_head = io_node;
+				} else {
+					err("Got NO IO resource(length=0x%x)\n", base);
+					return -ENOMEM;
+				}
+			} else {	/* map MEM */
+				int prefetchable = 1;
+				struct pci_resource **res_node = &amp;func-&gt;p_mem_head;
+				char *res_type_str = "PMEM";
+				u32	temp_register2;
+
+				if (!(temp_register &amp; PCI_BASE_ADDRESS_MEM_PREFETCH)) {
+					prefetchable = 0;
+					res_node = &amp;func-&gt;mem_head;
+					res_type_str++;
+				}
+
+				base = temp_register &amp; 0xFFFFFFF0;
+				base = ~base + 1;
+
+				switch (temp_register &amp; PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+				case PCI_BASE_ADDRESS_MEM_TYPE_32:
+					dbg("NEED 32 %s bar=0x%x(length=0x%x)\n", res_type_str, temp_register, base);
+
+					if (prefetchable &amp;&amp; resources-&gt;p_mem_head)
+						mem_node=get_resource(&amp;(resources-&gt;p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node=get_resource(&amp;(resources-&gt;mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base = (u32)mem_node-&gt;base; 
+						mem_node-&gt;next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 32 %s base=0x%x(length=0x%x)\n", res_type_str, mem_node-&gt;base, 
+							mem_node-&gt;length);
+					} else {
+						err("Got NO 32 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				case PCI_BASE_ADDRESS_MEM_TYPE_64:
+					rc = pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &amp;temp_register2);
+					dbg("NEED 64 %s bar=0x%x:%x(length=0x%x)\n", res_type_str, temp_register2, 
+						temp_register, base);
+
+					if (prefetchable &amp;&amp; resources-&gt;p_mem_head)
+						mem_node = get_resource(&amp;(resources-&gt;p_mem_head), (ulong)base);
+					else {
+						if (prefetchable)
+							dbg("using MEM for PMEM\n");
+						mem_node = get_resource(&amp;(resources-&gt;mem_head), (ulong)base);
+					}
+
+					/* allocate the resource to the board */
+					if (mem_node) {
+						base64 = mem_node-&gt;base; 
+						mem_node-&gt;next = *res_node;
+						*res_node = mem_node;
+						dbg("Got 64 %s base=0x%x:%x(length=%x)\n", res_type_str, (u32)(base64 &gt;&gt; 32), 
+							(u32)base64, mem_node-&gt;length);
+					} else {
+						err("Got NO 64 %s resource(length=0x%x)\n", res_type_str, base);
+						return -ENOMEM;
+					}
+					break;
+				default:
+					dbg("reserved BAR type=0x%x\n", temp_register);
+					break;
+				}
+
+			}
+
+			if (base64) {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+				cloop += 4;
+				base64 &gt;&gt;= 32;
+
+				if (base64) {
+					dbg("%s: high dword of base64(0x%x) set to 0\n", __FUNCTION__, (u32)base64);
+					base64 = 0x0L;
+				}
+
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, (u32)base64);
+			} else {
+				rc = pci_bus_write_config_dword(pci_bus, devfn, cloop, base);
+			}
+		}		/* End of base register loop */
+
+#if defined(CONFIG_X86_64)
+		/* Figure out which interrupt pin this function uses */
+		rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &amp;temp_byte);
+
+		/* If this function needs an interrupt and we are behind a bridge
+		   and the pin is tied to something that's alread mapped,
+		   set this one the same
+		 */
+		if (temp_byte &amp;&amp; resources-&gt;irqs &amp;&amp; 
+		    (resources-&gt;irqs-&gt;valid_INT &amp; 
+		     (0x01 &lt;&lt; ((temp_byte + resources-&gt;irqs-&gt;barber_pole - 1) &amp; 0x03)))) {
+			/* We have to share with something already set up */
+			IRQ = resources-&gt;irqs-&gt;interrupt[(temp_byte + resources-&gt;irqs-&gt;barber_pole - 1) &amp; 0x03];
+		} else {
+			/* Program IRQ based on card type */
+			rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &amp;class_code);
+
+			if (class_code == PCI_BASE_CLASS_STORAGE) {
+				IRQ = shpchp_disk_irq;
+			} else {
+				IRQ = shpchp_nic_irq;
+			}
+		}
+
+		/* IRQ Line */
+		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
+
+		if (!behind_bridge) {
+			rc = shpchp_set_irq(func-&gt;bus, func-&gt;device, temp_byte + 0x09, IRQ);
+			if (rc)
+				return(1);
+		} else {
+			/* TBD - this code may also belong in the other clause of this If statement */
+			resources-&gt;irqs-&gt;interrupt[(temp_byte + resources-&gt;irqs-&gt;barber_pole - 1) &amp; 0x03] = IRQ;
+			resources-&gt;irqs-&gt;valid_INT |= 0x01 &lt;&lt; (temp_byte + resources-&gt;irqs-&gt;barber_pole - 1) &amp; 0x03;
+		}
+#endif
+		/* Disable ROM base Address */
+		temp_word = 0x00L;
+		rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word);
+
+		/* Set HP parameters (Cache Line Size, Latency Timer) */
+		rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+		if (rc)
+			return rc;
+
+		shpchprm_enable_card(ctrl, func, PCI_HEADER_TYPE_NORMAL);
+
+		dbg("PCI function Hot-Added s:b:d:f(%02x:%02x:%02x:%02x)\n", ctrl-&gt;seg, func-&gt;bus, func-&gt;device, func-&gt;function);
+	}			/* End of Not-A-Bridge else */
+	else {
+		/* It's some strange type of PCI adapter (Cardbus?) */
+		return(DEVICE_TYPE_NOT_SUPPORTED);
+	}
+
+	func-&gt;configured = 1;
+
+	return 0;
+}
+
diff -puN /dev/null drivers/pci/hotplug/shpchp.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchp.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,467 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;,&lt;dely.l.sy@intel.com&gt;
+ *
+ */
+#ifndef _SHPCHP_H
+#define _SHPCHP_H
+
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;asm/semaphore.h&gt;
+#include &lt;asm/io.h&gt;		
+#include "pci_hotplug.h"
+
+#if !defined(CONFIG_HOTPLUG_PCI_SHPC_MODULE)
+	#define MY_NAME	"shpchp"
+#else
+	#define MY_NAME	THIS_MODULE-&gt;name
+#endif
+
+extern int shpchp_poll_mode;
+extern int shpchp_poll_time;
+extern int shpchp_debug;
+
+/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
+#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+
+struct pci_func {
+	struct pci_func *next;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 is_a_board;
+	u16 status;
+	u8 configured;
+	u8 switch_save;
+	u8 presence_save;
+	u32 base_length[0x06];
+	u8 base_type[0x06];
+	u16 reserved2;
+	u32 config_space[0x20];
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev* pci_dev;
+};
+
+#define SLOT_MAGIC	0x67267321
+struct slot {
+	u32 magic;
+	struct slot *next;
+	u8 bus;
+	u8 device;
+	u32 number;
+	u8 is_a_board;
+	u8 configured;
+	u8 state;
+	u8 switch_save;
+	u8 presence_save;
+	u32 capabilities;
+	u16 reserved2;
+	struct timer_list task_event;
+	u8 hp_slot;
+	struct controller *ctrl;
+	struct hpc_ops *hpc_ops;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head	slot_list;
+};
+
+struct pci_resource {
+	struct pci_resource * next;
+	u32 base;
+	u32 length;
+};
+
+struct event_info {
+	u32 event_type;
+	u8 hp_slot;
+};
+
+struct controller {
+	struct controller *next;
+	struct semaphore crit_sect;	/* critical section semaphore */
+	void * hpc_ctlr_handle;		/* HPC controller handle */
+	int num_slots;			/* Number of slots on ctlr */
+	int slot_num_inc;		/* 1 or -1 */
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct pci_dev *pci_dev;
+	struct pci_bus *pci_bus;
+	struct event_info event_queue[10];
+	struct slot *slot;
+	struct hpc_ops *hpc_ops;
+	wait_queue_head_t queue;	/* sleep &amp; wake process */
+	u8 next_event;
+	u8 seg;
+	u8 bus;
+	u8 device;
+	u8 function;
+	u8 rev;
+	u8 slot_device_offset;
+	u8 add_support;
+	enum pci_bus_speed speed;
+	u32 first_slot;		/* First physical slot number */
+	u8 slot_bus;		/* Bus where the slots handled by this controller sit */
+	u8 push_flag;
+	u16 ctlrcap;
+	u16 vendor_id;
+};
+
+struct irq_mapping {
+	u8 barber_pole;
+	u8 valid_INT;
+	u8 interrupt[4];
+};
+
+struct resource_lists {
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	struct irq_mapping *irqs;
+};
+
+/* Define AMD SHPC ID  */
+#define PCI_DEVICE_ID_AMD_GOLAM_7450	0x7450 
+
+/* Define SHPC CAP ID - not defined in kernel yet */
+#define PCI_CAP_ID_SHPC			0x0C 
+
+#define INT_BUTTON_IGNORE		0
+#define INT_PRESENCE_ON			1
+#define INT_PRESENCE_OFF		2
+#define INT_SWITCH_CLOSE		3
+#define INT_SWITCH_OPEN			4
+#define INT_POWER_FAULT			5
+#define INT_POWER_FAULT_CLEAR		6
+#define INT_BUTTON_PRESS		7
+#define INT_BUTTON_RELEASE		8
+#define INT_BUTTON_CANCEL		9
+
+#define STATIC_STATE			0
+#define BLINKINGON_STATE		1
+#define BLINKINGOFF_STATE		2
+#define POWERON_STATE			3
+#define POWEROFF_STATE			4
+
+#define PCI_TO_PCI_BRIDGE_CLASS		0x00060400
+
+/* Error messages */
+#define INTERLOCK_OPEN			0x00000002
+#define ADD_NOT_SUPPORTED		0x00000003
+#define CARD_FUNCTIONING		0x00000005
+#define ADAPTER_NOT_SAME		0x00000006
+#define NO_ADAPTER_PRESENT		0x00000009
+#define NOT_ENOUGH_RESOURCES		0x0000000B
+#define DEVICE_TYPE_NOT_SUPPORTED	0x0000000C
+#define WRONG_BUS_FREQUENCY		0x0000000D
+#define POWER_FAILURE			0x0000000E
+
+#define REMOVE_NOT_SUPPORTED		0x00000003
+
+#define DISABLE_CARD			1
+
+/*
+ * error Messages
+ */
+#define msg_initialization_err	"Initialization failure, error=%d\n"
+#define msg_HPC_rev_error	"Unsupported revision of the PCI hot plug controller found.\n"
+#define msg_HPC_non_shpc	"The PCI hot plug controller is not supported by this driver.\n"
+#define msg_HPC_not_supported	"This system is not supported by this version of shpcphd mdoule. Upgrade to a newer version of shpchpd\n"
+#define msg_unable_to_save	"Unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n"
+#define msg_button_on		"PCI slot #%d - powering on due to button press.\n"
+#define msg_button_off		"PCI slot #%d - powering off due to button press.\n"
+#define msg_button_cancel	"PCI slot #%d - action canceled due to button press.\n"
+#define msg_button_ignore	"PCI slot #%d - button press ignored.  (action in progress...)\n"
+
+/* sysfs functions for the hotplug controller info */
+extern void shpchp_create_ctrl_files	(struct controller *ctrl);
+
+/* controller functions */
+extern void	shpchp_pushbutton_thread(unsigned long event_pointer);
+extern int	shpchprm_find_available_resources(struct controller *ctrl);
+extern int	shpchp_event_start_thread(void);
+extern void	shpchp_event_stop_thread(void);
+extern struct 	pci_func *shpchp_slot_create(unsigned char busnumber);
+extern struct 	pci_func *shpchp_slot_find(unsigned char bus, unsigned char device, unsigned char index);
+extern int	shpchp_enable_slot(struct slot *slot);
+extern int	shpchp_disable_slot(struct slot *slot);
+
+extern u8	shpchp_handle_attention_button(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_presence_change(u8 hp_slot, void *inst_id);
+extern u8	shpchp_handle_power_fault(u8 hp_slot, void *inst_id);
+
+/* resource functions */
+extern int	shpchp_resource_sort_and_combine(struct pci_resource **head);
+
+/* pci functions */
+extern int	shpchp_set_irq(u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num);
+/*extern int	shpchp_get_bus_dev(struct controller *ctrl, u8 *bus_num, u8 *dev_num, struct slot *slot);*/
+extern int	shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
+extern int	shpchp_save_used_resources(struct controller *ctrl, struct pci_func * func, int flag);
+extern int	shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot);
+extern void	shpchp_destroy_board_resources(struct pci_func * func);
+extern int	shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources);
+extern void	shpchp_destroy_resource_list(struct resource_lists * resources);
+extern int	shpchp_configure_device(struct controller* ctrl, struct pci_func* func);
+extern int	shpchp_unconfigure_device(struct pci_func* func);
+
+
+/* Global variables */
+extern struct controller *shpchp_ctrl_list;
+extern struct pci_func *shpchp_slot_list[256];
+
+/* These are added to support AMD shpc */
+extern u8 shpchp_nic_irq;
+extern u8 shpchp_disk_irq;
+
+struct ctrl_reg {
+	volatile u32 base_offset;
+	volatile u32 slot_avail1;
+	volatile u32 slot_avail2;
+	volatile u32 slot_config;
+	volatile u16 sec_bus_config;
+	volatile u8  msi_ctrl;
+	volatile u8  prog_interface;
+	volatile u16 cmd;
+	volatile u16 cmd_status;
+	volatile u32 intr_loc;
+	volatile u32 serr_loc;
+	volatile u32 serr_intr_enable;
+	volatile u32 slot1;
+	volatile u32 slot2;
+	volatile u32 slot3;
+	volatile u32 slot4;
+	volatile u32 slot5;
+	volatile u32 slot6;
+	volatile u32 slot7;
+	volatile u32 slot8;
+	volatile u32 slot9;
+	volatile u32 slot10;
+	volatile u32 slot11;
+	volatile u32 slot12;
+} __attribute__ ((packed));
+
+/* offsets to the controller registers based on the above structure layout */
+enum ctrl_offsets {
+	BASE_OFFSET =	offsetof(struct ctrl_reg, base_offset),
+	SLOT_AVAIL1 =	offsetof(struct ctrl_reg, slot_avail1),
+	SLOT_AVAIL2	=	offsetof(struct ctrl_reg, slot_avail2),
+	SLOT_CONFIG =	offsetof(struct ctrl_reg, slot_config),
+	SEC_BUS_CONFIG =	offsetof(struct ctrl_reg, sec_bus_config),
+	MSI_CTRL	=	offsetof(struct ctrl_reg, msi_ctrl),
+	PROG_INTERFACE =	offsetof(struct ctrl_reg, prog_interface),
+	CMD		=	offsetof(struct ctrl_reg, cmd),
+	CMD_STATUS	=	offsetof(struct ctrl_reg, cmd_status),
+	INTR_LOC	= 	offsetof(struct ctrl_reg, intr_loc),
+	SERR_LOC	= 	offsetof(struct ctrl_reg, serr_loc),
+	SERR_INTR_ENABLE =	offsetof(struct ctrl_reg, serr_intr_enable),
+	SLOT1 =		offsetof(struct ctrl_reg, slot1),
+	SLOT2 =		offsetof(struct ctrl_reg, slot2),
+	SLOT3 =		offsetof(struct ctrl_reg, slot3),
+	SLOT4 =		offsetof(struct ctrl_reg, slot4),
+	SLOT5 =		offsetof(struct ctrl_reg, slot5),
+	SLOT6 =		offsetof(struct ctrl_reg, slot6),		
+	SLOT7 =		offsetof(struct ctrl_reg, slot7),
+	SLOT8 =		offsetof(struct ctrl_reg, slot8),
+	SLOT9 =		offsetof(struct ctrl_reg, slot9),
+	SLOT10 =	offsetof(struct ctrl_reg, slot10),
+	SLOT11 =	offsetof(struct ctrl_reg, slot11),
+	SLOT12 =	offsetof(struct ctrl_reg, slot12),
+};
+typedef u8(*php_intr_callback_t) (unsigned int change_id, void *instance_id);
+struct php_ctlr_state_s {
+	struct php_ctlr_state_s *pnext;
+	struct pci_dev *pci_dev;
+	unsigned int irq;
+	unsigned long flags;	/* spinlock's */
+	u32 slot_device_offset;
+	u32 num_slots;
+    	struct timer_list	int_poll_timer;	/* Added for poll event */
+	php_intr_callback_t attention_button_callback;
+	php_intr_callback_t switch_change_callback;
+	php_intr_callback_t presence_change_callback;
+	php_intr_callback_t power_fault_callback;
+	void *callback_instance_id;
+	void *creg;				/* Ptr to controller register space */
+};
+/* Inline functions */
+
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static inline int slot_paranoia_check (struct slot *slot, const char *function)
+{
+	if (!slot) {
+		dbg("%s - slot == NULL", function);
+		return -1;
+	}
+	if (slot-&gt;magic != SLOT_MAGIC) {
+		dbg("%s - bad magic number for slot", function);
+		return -1;
+	}
+	if (!slot-&gt;hotplug_slot) {
+		dbg("%s - slot-&gt;hotplug_slot == NULL!", function);
+		return -1;
+	}
+	return 0;
+}
+
+static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
+{ 
+	struct slot *slot;
+
+	if (!hotplug_slot) {
+		dbg("%s - hotplug_slot == NULL\n", function);
+		return NULL;
+	}
+
+	slot = (struct slot *)hotplug_slot-&gt;private;
+	if (slot_paranoia_check (slot, function))
+                return NULL;
+	return slot;
+}
+
+static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
+{
+	struct slot *p_slot, *tmp_slot = NULL;
+
+	if (!ctrl)
+		return NULL;
+
+	p_slot = ctrl-&gt;slot;
+
+	dbg("p_slot = %p\n", p_slot);
+
+	while (p_slot &amp;&amp; (p_slot-&gt;device != device)) {
+		tmp_slot = p_slot;
+		p_slot = p_slot-&gt;next;
+		dbg("In while loop, p_slot = %p\n", p_slot);
+	}
+	if (p_slot == NULL) {
+		err("ERROR: shpchp_find_slot device=0x%x\n", device);
+		p_slot = tmp_slot;
+	}
+
+	return (p_slot);
+}
+
+static inline int wait_for_ctrl_irq (struct controller *ctrl)
+{
+    DECLARE_WAITQUEUE(wait, current);
+	int retval = 0;
+
+	dbg("%s : start\n",__FUNCTION__);
+
+	add_wait_queue(&amp;ctrl-&gt;queue, &amp;wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	if (!shpchp_poll_mode) {
+		/* Sleep for up to 1 second */
+		schedule_timeout(1*HZ);
+	} else {
+		/* Sleep for up to 1.5 second */
+		schedule_timeout(1.5*HZ);
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&amp;ctrl-&gt;queue, &amp;wait);
+	if (signal_pending(current))
+		retval =  -EINTR;
+
+	dbg("%s : end\n", __FUNCTION__);
+	return retval;
+}
+
+/* Puts node back in the resource list pointed to by head */
+static inline void return_resource(struct pci_resource **head, struct pci_resource *node)
+{
+	if (!node || !head)
+		return;
+	node-&gt;next = *head;
+	*head = node;
+}
+
+#define SLOT_NAME_SIZE 10
+
+static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
+{
+	snprintf(buffer, buffer_size, "%d", slot-&gt;number);
+}
+
+enum php_ctlr_type {
+	PCI,
+	ISA,
+	ACPI
+};
+
+int shpc_init( struct controller *ctrl, struct pci_dev *pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback);
+
+int shpc_get_ctlr_slot_config( struct controller *ctrl,
+		int *num_ctlr_slots,
+		int *first_device_num,
+		int *physical_slot_num,
+		int *updown,
+		int *flags);
+
+struct hpc_ops {
+	int	(*power_on_slot )		(struct slot *slot);
+	int	(*slot_enable )			(struct slot *slot);
+	int	(*slot_disable )		(struct slot *slot);
+	int	(*enable_all_slots)		(struct slot *slot);
+	int	(*pwr_on_all_slots)		(struct slot *slot);
+	int	(*set_bus_speed_mode)	(struct slot *slot, enum pci_bus_speed speed);
+	int	(*get_power_status)		(struct slot *slot, u8 *status);
+	int	(*get_attention_status)	(struct slot *slot, u8 *status);
+	int	(*set_attention_status)	(struct slot *slot, u8 status);
+	int	(*get_latch_status)		(struct slot *slot, u8 *status);
+	int	(*get_adapter_status)	(struct slot *slot, u8 *status);
+
+	int	(*get_max_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_cur_bus_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_adapter_speed)	(struct slot *slot, enum pci_bus_speed *speed);
+	int	(*get_mode1_ECC_cap)	(struct slot *slot, u8 *mode);
+	int	(*get_prog_int)			(struct slot *slot, u8 *prog_int);
+
+	int	(*query_power_fault)	(struct slot *slot);
+	void	(*green_led_on)		(struct slot *slot);
+	void	(*green_led_off)	(struct slot *slot);
+	void	(*green_led_blink)	(struct slot *slot);
+	void	(*release_ctlr)		(struct controller *ctrl);
+	int (*check_cmd_status)		(struct controller *ctrl);
+};
+
+#endif				/* _SHPCHP_H */
diff -puN /dev/null drivers/pci/hotplug/shpchp_hpc.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchp_hpc.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,1608 @@
+/*
+ * Standard PCI Hot Plug Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;,&lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/vmalloc.h&gt;
+#include &lt;linux/interrupt.h&gt;
+#include &lt;linux/spinlock.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;asm/system.h&gt;
+#include "shpchp.h"
+
+#ifdef DEBUG
+#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
+#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
+#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
+#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
+#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
+#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
+/* Redefine this flagword to set debug level */
+#define DEBUG_LEVEL            DBG_K_STANDARD
+
+#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
+
+#define DBG_PRINT( dbg_flags, args... )              \
+	do {                                             \
+	  if ( DEBUG_LEVEL &amp; ( dbg_flags ) )             \
+	  {                                              \
+	    int len;                                     \
+	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
+		  __FILE__, __LINE__, __FUNCTION__ );    \
+	    sprintf( __dbg_str_buf + len, args );        \
+	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
+	  }                                              \
+	} while (0)
+
+#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
+#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
+#else
+#define DEFINE_DBG_BUFFER
+#define DBG_ENTER_ROUTINE
+#define DBG_LEAVE_ROUTINE
+#endif				/* DEBUG */
+
+/* Slot Available Register I field definition */
+#define SLOT_33MHZ		0x0000001f
+#define SLOT_66MHZ_PCIX		0x00001f00
+#define SLOT_100MHZ_PCIX	0x001f0000
+#define SLOT_133MHZ_PCIX	0x1f000000
+
+/* Slot Available Register II field definition */
+#define SLOT_66MHZ		0x0000001f
+#define SLOT_66MHZ_PCIX_266	0x00000f00
+#define SLOT_100MHZ_PCIX_266	0x0000f000
+#define SLOT_133MHZ_PCIX_266	0x000f0000
+#define SLOT_66MHZ_PCIX_533	0x00f00000
+#define SLOT_100MHZ_PCIX_533	0x0f000000
+#define SLOT_133MHZ_PCIX_533	0xf0000000
+
+
+/* Secondary Bus Configuration Register */
+/* For PI = 1, Bits 0 to 2 have been encoded as follows to show current bus speed/mode */
+#define PCI_33MHZ		0x0
+#define PCI_66MHZ		0x1
+#define PCIX_66MHZ		0x2
+#define PCIX_100MHZ		0x3
+#define PCIX_133MHZ		0x4
+
+/* For PI = 2, Bits 0 to 3 have been encoded as follows to show current bus speed/mode */
+#define PCI_33MHZ		0x0
+#define PCI_66MHZ		0x1
+#define PCIX_66MHZ		0x2
+#define PCIX_100MHZ		0x3
+#define PCIX_133MHZ		0x4
+#define PCIX_66MHZ_ECC		0x5
+#define PCIX_100MHZ_ECC		0x6
+#define PCIX_133MHZ_ECC		0x7
+#define PCIX_66MHZ_266		0x8
+#define PCIX_100MHZ_266		0x9
+#define PCIX_133MHZ_266		0x0a
+#define PCIX_66MHZ_533		0x0b
+#define PCIX_100MHZ_533		0x0c
+#define PCIX_133MHZ_533		0x0d
+
+/* Slot Configuration */
+#define SLOT_NUM		0x0000001F
+#define	FIRST_DEV_NUM		0x00001F00
+#define PSN			0x07FF0000
+#define	UPDOWN			0x20000000
+#define	MRLSENSOR		0x40000000
+#define ATTN_BUTTON		0x80000000
+
+/* Slot Status Field Definitions */
+/* Slot State */
+#define PWR_ONLY		0x0001
+#define ENABLED			0x0002
+#define DISABLED		0x0003
+
+/* Power Indicator State */
+#define PWR_LED_ON		0x0004
+#define PWR_LED_BLINK		0x0008
+#define PWR_LED_OFF		0x000c
+
+/* Attention Indicator State */
+#define ATTEN_LED_ON		0x0010
+#define	ATTEN_LED_BLINK		0x0020
+#define ATTEN_LED_OFF		0x0030
+
+/* Power Fault */
+#define pwr_fault		0x0040
+
+/* Attention Button */
+#define ATTEN_BUTTON		0x0080
+
+/* MRL Sensor */
+#define MRL_SENSOR		0x0100
+
+/* 66 MHz Capable */
+#define IS_66MHZ_CAP		0x0200
+
+/* PRSNT1#/PRSNT2# */
+#define SLOT_EMP		0x0c00
+
+/* PCI-X Capability */
+#define NON_PCIX		0x0000
+#define PCIX_66			0x1000
+#define PCIX_133		0x3000
+#define PCIX_266		0x4000  /* For PI = 2 only */
+#define PCIX_533		0x5000	/* For PI = 2 only */
+
+/* SHPC 'write' operations/commands */
+
+/* Slot operation - 0x00h to 0x3Fh */
+
+#define NO_CHANGE		0x00
+
+/* Slot state - Bits 0 &amp; 1 of controller command register */
+#define SET_SLOT_PWR		0x01	
+#define SET_SLOT_ENABLE		0x02	
+#define SET_SLOT_DISABLE	0x03	
+
+/* Power indicator state - Bits 2 &amp; 3 of controller command register*/
+#define SET_PWR_ON		0x04	
+#define SET_PWR_BLINK		0x08	
+#define SET_PWR_OFF		0x0C	
+
+/* Attention indicator state - Bits 4 &amp; 5 of controller command register*/
+#define SET_ATTN_ON		0x010	
+#define SET_ATTN_BLINK		0x020
+#define SET_ATTN_OFF		0x030	
+
+/* Set bus speed/mode A - 0x40h to 0x47h */
+#define SETA_PCI_33MHZ		0x40
+#define SETA_PCI_66MHZ		0x41
+#define SETA_PCIX_66MHZ		0x42
+#define SETA_PCIX_100MHZ	0x43
+#define SETA_PCIX_133MHZ	0x44
+#define RESERV_1		0x45
+#define RESERV_2		0x46
+#define RESERV_3		0x47
+
+/* Set bus speed/mode B - 0x50h to 0x5fh */
+#define	SETB_PCI_33MHZ		0x50
+#define SETB_PCI_66MHZ		0x51
+#define SETB_PCIX_66MHZ_PM	0x52
+#define SETB_PCIX_100MHZ_PM	0x53
+#define SETB_PCIX_133MHZ_PM	0x54
+#define SETB_PCIX_66MHZ_EM	0x55
+#define SETB_PCIX_100MHZ_EM	0x56
+#define SETB_PCIX_133MHZ_EM	0x57
+#define SETB_PCIX_66MHZ_266	0x58
+#define SETB_PCIX_100MHZ_266	0x59
+#define SETB_PCIX_133MHZ_266	0x5a
+#define SETB_PCIX_66MHZ_533	0x5b
+#define SETB_PCIX_100MHZ_533	0x5c
+#define SETB_PCIX_133MHZ_533	0x5d
+
+
+/* Power-on all slots - 0x48h */
+#define SET_PWR_ON_ALL		0x48
+
+/* Enable all slots	- 0x49h */
+#define SET_ENABLE_ALL		0x49
+
+/*  SHPC controller command error code */
+#define SWITCH_OPEN		0x1
+#define INVALID_CMD		0x2
+#define INVALID_SPEED_MODE	0x4
+
+/* For accessing SHPC Working Register Set */
+#define DWORD_SELECT		0x2
+#define DWORD_DATA		0x4
+#define BASE_OFFSET		0x0
+
+/* Field Offset in Logical Slot Register - byte boundary */
+#define SLOT_EVENT_LATCH	0x2
+#define SLOT_SERR_INT_MASK	0x3
+
+static spinlock_t hpc_event_lock;
+
+DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
+static struct php_ctlr_state_s *php_ctlr_list_head = 0;	/* HPC state linked list */
+static int ctlr_seq_num = 0;	/* Controller sequenc # */
+static spinlock_t list_lock;
+
+static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+
+/* This is the interrupt polling timeout function. */
+static void int_poll_timeout(unsigned long lphp_ctlr)
+{
+    struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+
+    DBG_ENTER_ROUTINE
+
+    if ( !php_ctlr ) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+    }
+
+    /* Poll for interrupt events.  regs == NULL =&gt; polling */
+    shpc_isr( 0, (void *)php_ctlr, NULL );
+
+    init_timer(&amp;php_ctlr-&gt;int_poll_timer);
+	if (!shpchp_poll_time)
+		shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+
+    start_int_poll_timer(php_ctlr, shpchp_poll_time);  
+	
+	return;
+}
+
+/* This function starts the interrupt polling timer. */
+static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+{
+    if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return;
+	}
+
+    if ( ( seconds &lt;= 0 ) || ( seconds &gt; 60 ) )
+        seconds = 2;            /* Clamp to sane value */
+
+    php_ctlr-&gt;int_poll_timer.function = &amp;int_poll_timeout;
+    php_ctlr-&gt;int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
+    php_ctlr-&gt;int_poll_timer.expires = jiffies + seconds * HZ;
+    add_timer(&amp;php_ctlr-&gt;int_poll_timer);
+
+	return;
+}
+
+static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 cmd_status;
+	int retval = 0;
+	u16 temp_word;
+	int i;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!php_ctlr) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	for (i = 0; i &lt; 10; i++) {
+		cmd_status = readw(php_ctlr-&gt;creg + CMD_STATUS);
+		
+		if (!(cmd_status &amp; 0x1))
+			break;
+		/*  Check every 0.1 sec for a total of 1 sec*/
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ/10);
+	}
+
+	cmd_status = readw(php_ctlr-&gt;creg + CMD_STATUS);
+	
+	if (cmd_status &amp; 0x1) { 
+		/* After 1 sec and and the controller is still busy */
+		err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
+		return -1;
+	}
+
+	++t_slot;
+	temp_word =  (t_slot &lt;&lt; 8) | (cmd &amp; 0xFF);
+	dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
+	
+	/* To make sure the Controller Busy bit is 0 before we send out the
+	 * command. 
+	 */
+	writew(temp_word, php_ctlr-&gt;creg + CMD);
+	dbg("%s: temp_word written %x\n", __FUNCTION__, temp_word);
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_check_cmd_status(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl-&gt;hpc_ctlr_handle;
+	u16 cmd_status;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	cmd_status = readw(php_ctlr-&gt;creg + CMD_STATUS) &amp; 0x000F;
+	
+	switch (cmd_status &gt;&gt; 1) {
+	case 0:
+		retval = 0;
+		break;
+	case 1:
+		retval = SWITCH_OPEN;
+		err("%s: Switch opened!\n", __FUNCTION__);
+		break;
+	case 2:
+		retval = INVALID_CMD;
+		err("%s: Invalid HPC command!\n", __FUNCTION__);
+		break;
+	case 4:
+		retval = INVALID_SPEED_MODE;
+		err("%s: Invalid bus speed/mode!\n", __FUNCTION__);
+		break;
+	default:
+		retval = cmd_status;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_attention_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 atten_led_state;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*(slot-&gt;hp_slot));
+	slot_status = (u16) slot_reg;
+	atten_led_state = (slot_status &amp; 0x0030) &gt;&gt; 4;
+
+	switch (atten_led_state) {
+	case 0:
+		*status = 0xFF;	/* Reserved */
+		break;
+	case 1:
+		*status = 1;	/* On */
+		break;
+	case 2:
+		*status = 2;	/* Blink */
+		break;
+	case 3:
+		*status = 0;	/* Off */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_power_status(struct slot * slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 slot_state;
+	int	retval = 0;
+	
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*(slot-&gt;hp_slot));
+	slot_status = (u16) slot_reg;
+	slot_state = (slot_status &amp; 0x0003);
+
+	switch (slot_state) {
+	case 0:
+		*status = 0xFF;
+		break;
+	case 1:
+		*status = 2;	/* Powered only */
+		break;
+	case 2:
+		*status = 1;	/* Enabled */
+		break;
+	case 3:
+		*status = 0;	/* Disabled */
+		break;
+	default:
+		*status = 0xFF;
+		break;
+	}
+
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+
+static int hpc_get_latch_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*(slot-&gt;hp_slot));
+	slot_status = (u16)slot_reg;
+
+	*status = ((slot_status &amp; 0x0100) == 0) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_status(struct slot *slot, u8 *status)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 card_state;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*(slot-&gt;hp_slot));
+	slot_status = (u16)slot_reg;
+	card_state = (u8)((slot_status &amp; 0x0C00) &gt;&gt; 10);
+	*status = (card_state != 0x3) ? 1 : 0;
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*prog_int = readb(php_ctlr-&gt;creg + PROG_INTERFACE);
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status, sec_bus_status;
+	u8 m66_cap, pcix_cap, pi;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	
+	pi = readb(php_ctlr-&gt;creg + PROG_INTERFACE);
+	slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*(slot-&gt;hp_slot));
+	dbg("%s: pi = %d, slot_reg = %x\n", __FUNCTION__, pi, slot_reg);
+	slot_status = (u16) slot_reg;
+	dbg("%s: slot_status = %x\n", __FUNCTION__, slot_status);
+	sec_bus_status = readw(php_ctlr-&gt;creg + SEC_BUS_CONFIG);
+
+	pcix_cap = (u8) ((slot_status &amp; 0x3000) &gt;&gt; 12);
+	dbg("%s:  pcix_cap = %x\n", __FUNCTION__, pcix_cap);
+	m66_cap = (u8) ((slot_status &amp; 0x0200) &gt;&gt; 9);
+	dbg("%s:  m66_cap = %x\n", __FUNCTION__, m66_cap);
+
+
+	if (pi == 2) {
+		switch (pcix_cap) {
+		case 0:
+			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+			break;
+		case 1:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			*value = PCI_SPEED_133MHz_PCIX;
+			break;
+		case 4:
+			*value = PCI_SPEED_133MHz_PCIX_266;	
+			break;
+		case 5:
+			*value = PCI_SPEED_133MHz_PCIX_533;	
+			break;
+		case 2:	/* Reserved */
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			break;
+		}
+	} else {
+		switch (pcix_cap) {
+		case 0:
+			*value = m66_cap ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+			break;
+		case 1:
+			*value = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			*value = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 2:	/* Reserved */
+		default:
+			*value = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			break;
+		}
+	}
+
+	dbg("Adapter speed = %d\n", *value);
+	
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u16 sec_bus_status;
+	u8 pi;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr-&gt;creg + PROG_INTERFACE);
+	sec_bus_status = readw(php_ctlr-&gt;creg + SEC_BUS_CONFIG);
+
+	if (pi == 2) {
+		*mode = (sec_bus_status &amp; 0x0100) &gt;&gt; 7;
+	} else {
+		retval = -1;
+	}
+
+	dbg("Mode 1 ECC cap = %d\n", *mode);
+	
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_query_power_fault(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u32 slot_reg;
+	u16 slot_status;
+	u8 pwr_fault_state, status;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*(slot-&gt;hp_slot));
+	slot_status = (u16) slot_reg;
+	pwr_fault_state = (slot_status &amp; 0x0040) &gt;&gt; 7;
+	status = (pwr_fault_state == 1) ? 0 : 1;
+
+	DBG_LEAVE_ROUTINE
+	/* Note: Logic 0 =&gt; fault */
+	return status;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd = 0;
+	int rc = 0;
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	switch (value) {
+		case 0 :	
+			slot_cmd = 0x30;	/* OFF */
+			break;
+		case 1:
+			slot_cmd = 0x10;	/* ON */
+			break;
+		case 2:
+			slot_cmd = 0x20;	/* BLINK */
+			break;
+		default:
+			return -1;
+	}
+
+	shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+	
+	return rc;
+}
+
+
+static void hpc_set_green_led_on(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x04;
+
+	shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_off(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x0C;
+
+	shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+
+	return;
+}
+
+static void hpc_set_green_led_blink(struct slot *slot)
+{
+	struct php_ctlr_state_s *php_ctlr =(struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd;
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return ;
+	}
+
+	slot_cmd = 0x08;
+
+	shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+
+	return;
+}
+
+int shpc_get_ctlr_slot_config(struct controller *ctrl,
+	int *num_ctlr_slots,	/* number of slots in this HPC			*/
+	int *first_device_num,	/* PCI dev num of the first slot in this SHPC	*/
+	int *physical_slot_num,	/* phy slot num of the first slot in this SHPC	*/
+	int *updown,		/* physical_slot_num increament: 1 or -1	*/
+	int *flags)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl-&gt;hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	*first_device_num = php_ctlr-&gt;slot_device_offset;	/* Obtained in shpc_init() */
+	*num_ctlr_slots = php_ctlr-&gt;num_slots;			/* Obtained in shpc_init() */
+
+	*physical_slot_num = (readl(php_ctlr-&gt;creg + SLOT_CONFIG) &amp; PSN) &gt;&gt; 16;
+	dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
+	*updown = ((readl(php_ctlr-&gt;creg + SLOT_CONFIG) &amp; UPDOWN ) &gt;&gt; 29) ? 1 : -1;	
+
+	DBG_LEAVE_ROUTINE 
+	return 0;
+}
+
+static void hpc_release_ctlr(struct controller *ctrl)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) ctrl-&gt;hpc_ctlr_handle;
+	struct php_ctlr_state_s *p, *p_prev;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return ;
+	}
+
+	if (shpchp_poll_mode) {
+	    del_timer(&amp;php_ctlr-&gt;int_poll_timer);
+	} else {	
+		if (php_ctlr-&gt;irq) {
+			free_irq(php_ctlr-&gt;irq, ctrl);
+			php_ctlr-&gt;irq = 0;
+		}
+	}
+	if (php_ctlr-&gt;pci_dev) {
+		dbg("%s: before calling iounmap &amp; release_mem_region\n", __FUNCTION__);
+		iounmap(php_ctlr-&gt;creg);
+		release_mem_region(pci_resource_start(php_ctlr-&gt;pci_dev, 0), pci_resource_len(php_ctlr-&gt;pci_dev, 0));
+		dbg("%s: before calling iounmap &amp; release_mem_region\n", __FUNCTION__);
+		php_ctlr-&gt;pci_dev = 0;
+	}
+
+	spin_lock(&amp;list_lock);
+	p = php_ctlr_list_head;
+	p_prev = NULL;
+	while (p) {
+		if (p == php_ctlr) {
+			if (p_prev)
+				p_prev-&gt;pnext = p-&gt;pnext;
+			else
+				php_ctlr_list_head = p-&gt;pnext;
+			break;
+		} else {
+			p_prev = p;
+			p = p-&gt;pnext;
+		}
+	}
+	spin_unlock(&amp;list_lock);
+
+	kfree(php_ctlr);
+
+DBG_LEAVE_ROUTINE
+			  
+}
+
+static int hpc_power_on_slot(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	slot_cmd = 0x01;
+
+	retval = shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_slot_enable(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+	/* 3A =&gt; Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
+	slot_cmd = 0x3A;  
+
+	retval = shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_slot_disable(struct slot * slot)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	u8 slot_cmd;
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	/* 1F =&gt; Slot - Disable, Power Indicator - Off, Attention Indicator - On */
+	slot_cmd = 0x1F;
+
+	retval = shpc_write_cmd(slot, slot-&gt;hp_slot, slot_cmd);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_enable_all_slots( struct slot *slot )
+{
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	retval = shpc_write_cmd(slot, 0, SET_ENABLE_ALL);
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+
+	return retval;
+}
+
+static int hpc_pwr_on_all_slots(struct slot *slot)
+{
+	int retval = 0;
+
+	DBG_ENTER_ROUTINE 
+
+	retval = shpc_write_cmd(slot, 0, SET_PWR_ON_ALL);
+
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
+{
+	u8 slot_cmd;
+	u8 pi;
+	int retval = 0;
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+
+	DBG_ENTER_ROUTINE 
+	
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr-&gt;creg + PROG_INTERFACE);
+	
+	if (pi == 1) {
+		switch (value) {
+		case 0:
+			slot_cmd = SETA_PCI_33MHZ;
+			break;
+		case 1:
+			slot_cmd = SETA_PCI_66MHZ;
+			break;
+		case 2:
+			slot_cmd = SETA_PCIX_66MHZ;
+			break;
+		case 3:
+			slot_cmd = SETA_PCIX_100MHZ;	
+			break;
+		case 4:
+			slot_cmd = SETA_PCIX_133MHZ;	
+			break;
+		default:
+			slot_cmd = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			return retval;	
+		}
+	} else {
+		switch (value) {
+		case 0:
+			slot_cmd = SETB_PCI_33MHZ;
+			break;
+		case 1:
+			slot_cmd = SETB_PCI_66MHZ;
+			break;
+		case 2:
+			slot_cmd = SETB_PCIX_66MHZ_PM;
+			break;
+		case 3:
+			slot_cmd = SETB_PCIX_100MHZ_PM;	
+			break;
+		case 4:
+			slot_cmd = SETB_PCIX_133MHZ_PM;	
+			break;
+		case 5:
+			slot_cmd = SETB_PCIX_66MHZ_EM;	
+			break;
+		case 6:
+			slot_cmd = SETB_PCIX_100MHZ_EM;	
+			break;
+		case 7:
+			slot_cmd = SETB_PCIX_133MHZ_EM;	
+			break;
+		case 8:
+			slot_cmd = SETB_PCIX_66MHZ_266;	
+			break;
+		case 0x9:
+			slot_cmd = SETB_PCIX_100MHZ_266;	
+			break;
+		case 0xa:
+			slot_cmd = SETB_PCIX_133MHZ_266;	
+			break;
+		case 0xb:
+			slot_cmd = SETB_PCIX_66MHZ_533;	
+			break;
+		case 0xc:
+			slot_cmd = SETB_PCIX_100MHZ_533;	
+			break;
+		case 0xd:
+			slot_cmd = SETB_PCIX_133MHZ_533;	
+			break;
+		default:
+			slot_cmd = PCI_SPEED_UNKNOWN;
+			retval = -ENODEV;
+			return retval;	
+		}
+
+	}
+	retval = shpc_write_cmd(slot, 0, slot_cmd);
+	if (retval) {
+		err("%s: Write command failed!\n", __FUNCTION__);
+		return -1;
+	}
+
+	DBG_LEAVE_ROUTINE
+	return retval;
+}
+
+static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+{
+	struct controller *ctrl = NULL;
+	struct php_ctlr_state_s *php_ctlr;
+	u8 schedule_flag = 0;
+	u8 temp_byte;
+	u32 temp_dword, intr_loc, intr_loc2;
+	int hp_slot;
+
+	if (!dev_id)
+		return IRQ_NONE;
+
+	if (!shpchp_poll_mode) { 
+		ctrl = (struct controller *)dev_id;
+		php_ctlr = ctrl-&gt;hpc_ctlr_handle;
+	} else 
+		php_ctlr = (struct php_ctlr_state_s *) dev_id;
+
+	if (!php_ctlr || !php_ctlr-&gt;creg)
+		return IRQ_NONE;
+
+	/* Check to see if it was our interrupt */
+	intr_loc = readl(php_ctlr-&gt;creg + INTR_LOC);  
+
+	if (!intr_loc)
+		return IRQ_NONE;
+	dbg("%s: shpc_isr proceeds\n", __FUNCTION__);
+	dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 
+
+	/* Mask Global Interrupt Mask - see implementation note on p. 139 */
+	/* of SHPC spec rev 1.0*/
+	temp_dword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+	dbg("%s: Before masking global interrupt, temp_dword = %x\n",
+		__FUNCTION__, temp_dword); 
+	temp_dword |= 0x00000001;
+	dbg("%s: After masking global interrupt, temp_dword = %x\n",
+		__FUNCTION__, temp_dword); 
+	writel(temp_dword, php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+
+	intr_loc2 = readl(php_ctlr-&gt;creg + INTR_LOC);  
+	dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+
+	if (intr_loc &amp; 0x0001) {
+		/* 
+		 * Command Complete Interrupt Pending 
+		 * RO only - clear by writing 0 to the Command Completion
+		 * Detect bit in Controller SERR-INT register
+		 */
+		temp_dword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+		dbg("%s: Before clearing CCIP, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &amp;= 0xfffeffff;
+		dbg("%s: After clearing CCIP, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+		wake_up_interruptible(&amp;ctrl-&gt;queue);
+	}
+
+	if ((intr_loc = (intr_loc &gt;&gt; 1)) == 0) {
+		/* Unmask Global Interrupt Mask */
+		temp_dword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+		dbg("%s: 1-Before unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		temp_dword &amp;= 0xfffffffe;
+		dbg("%s: 1-After unmasking global interrupt, temp_dword = %x\n",
+			__FUNCTION__, temp_dword); 
+		writel(temp_dword, php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+
+		return IRQ_NONE;
+	}
+
+	for (hp_slot = 0; hp_slot &lt; ctrl-&gt;num_slots; hp_slot++) { 
+	/* To find out which slot has interrupt pending */
+		if ((intr_loc &gt;&gt; hp_slot) &amp; 0x01) {
+			temp_dword = readl(php_ctlr-&gt;creg + SLOT1 + (4*hp_slot));
+			dbg("%s: Slot %x with intr, temp_dword = %x\n",
+				__FUNCTION__, hp_slot, temp_dword); 
+			temp_byte = (temp_dword &gt;&gt; 16) &amp; 0xFF;
+			dbg("%s: Slot with intr, temp_byte = %x\n",
+				__FUNCTION__, temp_byte); 
+			if ((php_ctlr-&gt;switch_change_callback) &amp;&amp; (temp_byte &amp; 0x08))
+				schedule_flag += php_ctlr-&gt;switch_change_callback(
+					hp_slot, php_ctlr-&gt;callback_instance_id);
+			if ((php_ctlr-&gt;attention_button_callback) &amp;&amp; (temp_byte &amp; 0x04))
+				schedule_flag += php_ctlr-&gt;attention_button_callback(
+					hp_slot, php_ctlr-&gt;callback_instance_id);
+			if ((php_ctlr-&gt;presence_change_callback) &amp;&amp; (temp_byte &amp; 0x01))
+				schedule_flag += php_ctlr-&gt;presence_change_callback(
+					hp_slot , php_ctlr-&gt;callback_instance_id);
+			if ((php_ctlr-&gt;power_fault_callback) &amp;&amp; (temp_byte &amp; 0x12))
+				schedule_flag += php_ctlr-&gt;power_fault_callback(
+					hp_slot, php_ctlr-&gt;callback_instance_id);
+			
+			/* Clear all slot events */
+			temp_dword = 0xe01fffff;
+			dbg("%s: Clearing slot events, temp_dword = %x\n",
+				__FUNCTION__, temp_dword); 
+			writel(temp_dword, php_ctlr-&gt;creg + SLOT1 + (4*hp_slot));
+
+			intr_loc2 = readl(php_ctlr-&gt;creg + INTR_LOC);  
+			dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+		}
+	}
+	/* Unmask Global Interrupt Mask */
+	temp_dword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+	dbg("%s: 2-Before unmasking global interrupt, temp_dword = %x\n",
+		__FUNCTION__, temp_dword); 
+	temp_dword &amp;= 0xfffffffe;
+	dbg("%s: 2-After unmasking global interrupt, temp_dword = %x\n",
+		__FUNCTION__, temp_dword); 
+	writel(temp_dword, php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+	
+	return IRQ_HANDLED;
+}
+
+static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+	int retval = 0;
+	u8 pi;
+	u32 slot_avail1, slot_avail2;
+	int slot_num;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr-&gt;creg + PROG_INTERFACE);
+	slot_avail1 = readl(php_ctlr-&gt;creg + SLOT_AVAIL1);
+	slot_avail2 = readl(php_ctlr-&gt;creg + SLOT_AVAIL2);
+
+	if (pi == 2) {
+		if ((slot_num = ((slot_avail2 &amp; SLOT_133MHZ_PCIX_533) &gt;&gt; 27)  ) != 0 )
+			bus_speed = PCIX_133MHZ_533;
+		else if ((slot_num = ((slot_avail2 &amp; SLOT_100MHZ_PCIX_533) &gt;&gt; 23)  ) != 0 )
+			bus_speed = PCIX_100MHZ_533;
+		else if ((slot_num = ((slot_avail2 &amp; SLOT_66MHZ_PCIX_533) &gt;&gt; 19)  ) != 0 )
+			bus_speed = PCIX_66MHZ_533;
+		else if ((slot_num = ((slot_avail2 &amp; SLOT_133MHZ_PCIX_266) &gt;&gt; 15)  ) != 0 )
+			bus_speed = PCIX_133MHZ_266;
+		else if ((slot_num = ((slot_avail2 &amp; SLOT_100MHZ_PCIX_266) &gt;&gt; 11)  ) != 0 )
+			bus_speed = PCIX_100MHZ_266;
+		else if ((slot_num = ((slot_avail2 &amp; SLOT_66MHZ_PCIX_266) &gt;&gt; 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ_266;
+		else if ((slot_num = ((slot_avail1 &amp; SLOT_133MHZ_PCIX) &gt;&gt; 23)  ) != 0 )
+			bus_speed = PCIX_133MHZ;
+		else if ((slot_num = ((slot_avail1 &amp; SLOT_100MHZ_PCIX) &gt;&gt; 15)  ) != 0 )
+			bus_speed = PCIX_100MHZ;
+		else if ((slot_num = ((slot_avail1 &amp; SLOT_66MHZ_PCIX) &gt;&gt; 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ;
+		else if ((slot_num = (slot_avail2 &amp; SLOT_66MHZ)) != 0 )
+			bus_speed = PCI_66MHZ;
+		else if ((slot_num = (slot_avail1 &amp; SLOT_33MHZ)) != 0 )
+			bus_speed = PCI_33MHZ;
+		else bus_speed = PCI_SPEED_UNKNOWN;
+	} else {
+		if ((slot_num = ((slot_avail1 &amp; SLOT_133MHZ_PCIX) &gt;&gt; 23)  ) != 0 )
+			bus_speed = PCIX_133MHZ;
+		else if ((slot_num = ((slot_avail1 &amp; SLOT_100MHZ_PCIX) &gt;&gt; 15)  ) != 0 )
+			bus_speed = PCIX_100MHZ;
+		else if ((slot_num = ((slot_avail1 &amp; SLOT_66MHZ_PCIX) &gt;&gt; 7)  ) != 0 )
+			bus_speed = PCIX_66MHZ;
+		else if ((slot_num = (slot_avail2 &amp; SLOT_66MHZ)) != 0 )
+			bus_speed = PCI_66MHZ;
+		else if ((slot_num = (slot_avail1 &amp; SLOT_33MHZ)) != 0 )
+			bus_speed = PCI_33MHZ;
+		else bus_speed = PCI_SPEED_UNKNOWN;
+	}
+
+	*value = bus_speed;
+	dbg("Max bus speed = %d\n", bus_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
+{
+	struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *) slot-&gt;ctrl-&gt;hpc_ctlr_handle;
+	enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
+	u16 sec_bus_status;
+	int retval = 0;
+	u8 pi;
+
+	DBG_ENTER_ROUTINE 
+
+	if (!slot-&gt;ctrl-&gt;hpc_ctlr_handle) {
+		err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
+		return -1;
+	}
+
+	if (slot-&gt;hp_slot &gt;= php_ctlr-&gt;num_slots) {
+		err("%s: Invalid HPC slot number!\n", __FUNCTION__);
+		return -1;
+	}
+
+	pi = readb(php_ctlr-&gt;creg + PROG_INTERFACE);
+	sec_bus_status = readw(php_ctlr-&gt;creg + SEC_BUS_CONFIG);
+
+	if (pi == 2) {
+		switch (sec_bus_status &amp; 0x000f) {
+		case 0:
+			bus_speed = PCI_SPEED_33MHz;
+			break;
+		case 1:
+			bus_speed = PCI_SPEED_66MHz;
+			break;
+		case 2:
+			bus_speed = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			bus_speed = PCI_SPEED_100MHz_PCIX;	
+			break;
+		case 4:
+			bus_speed = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 5:
+			bus_speed = PCI_SPEED_66MHz_PCIX_ECC;
+			break;
+		case 6:
+			bus_speed = PCI_SPEED_100MHz_PCIX_ECC;
+			break;
+		case 7:
+			bus_speed = PCI_SPEED_133MHz_PCIX_ECC;	
+			break;
+		case 8:
+			bus_speed = PCI_SPEED_66MHz_PCIX_266;	
+			break;
+		case 9:
+			bus_speed = PCI_SPEED_100MHz_PCIX_266;	
+			break;
+		case 0xa:
+			bus_speed = PCI_SPEED_133MHz_PCIX_266;	
+			break;
+		case 0xb:
+			bus_speed = PCI_SPEED_66MHz_PCIX_533;	
+			break;
+		case 0xc:
+			bus_speed = PCI_SPEED_100MHz_PCIX_533;	
+			break;
+		case 0xd:
+			bus_speed = PCI_SPEED_133MHz_PCIX_533;	
+			break;
+		case 0xe:
+		case 0xf:
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		}
+	} else {
+		/* In the case where pi is undefined, default it to 1 */ 
+		switch (sec_bus_status &amp; 0x0007) {
+		case 0:
+			bus_speed = PCI_SPEED_33MHz;
+			break;
+		case 1:
+			bus_speed = PCI_SPEED_66MHz;
+			break;
+		case 2:
+			bus_speed = PCI_SPEED_66MHz_PCIX;
+			break;
+		case 3:
+			bus_speed = PCI_SPEED_100MHz_PCIX;	
+			break;
+		case 4:
+			bus_speed = PCI_SPEED_133MHz_PCIX;	
+			break;
+		case 5:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
+			break;
+		case 6:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */
+			break;
+		case 7:
+			bus_speed = PCI_SPEED_UNKNOWN;		/*	Reserved */	
+			break;
+		default:
+			bus_speed = PCI_SPEED_UNKNOWN;
+			break;
+		}
+	}
+
+	*value = bus_speed;
+	dbg("Current bus speed = %d\n", bus_speed);
+	DBG_LEAVE_ROUTINE 
+	return retval;
+}
+
+static struct hpc_ops shpchp_hpc_ops = {
+	.power_on_slot			= hpc_power_on_slot,
+	.slot_enable			= hpc_slot_enable,
+	.slot_disable			= hpc_slot_disable,
+	.enable_all_slots		= hpc_enable_all_slots,
+	.pwr_on_all_slots		= hpc_pwr_on_all_slots,
+	.set_bus_speed_mode		= hpc_set_bus_speed_mode,	  
+	.set_attention_status	= hpc_set_attention_status,
+	.get_power_status		= hpc_get_power_status,
+	.get_attention_status	= hpc_get_attention_status,
+	.get_latch_status		= hpc_get_latch_status,
+	.get_adapter_status		= hpc_get_adapter_status,
+
+	.get_max_bus_speed		= hpc_get_max_bus_speed,
+	.get_cur_bus_speed		= hpc_get_cur_bus_speed,
+	.get_adapter_speed		= hpc_get_adapter_speed,
+	.get_mode1_ECC_cap		= hpc_get_mode1_ECC_cap,
+	.get_prog_int			= hpc_get_prog_int,
+
+	.query_power_fault		= hpc_query_power_fault,
+	.green_led_on			= hpc_set_green_led_on,
+	.green_led_off			= hpc_set_green_led_off,
+	.green_led_blink		= hpc_set_green_led_blink,
+	
+	.release_ctlr			= hpc_release_ctlr,
+	.check_cmd_status		= hpc_check_cmd_status,
+};
+
+int shpc_init(struct controller * ctrl,
+		struct pci_dev * pdev,
+		php_intr_callback_t attention_button_callback,
+		php_intr_callback_t switch_change_callback,
+		php_intr_callback_t presence_change_callback,
+		php_intr_callback_t power_fault_callback)
+{
+	struct php_ctlr_state_s *php_ctlr, *p;
+	void *instance_id = ctrl;
+	int rc;
+	u8 hp_slot;
+	static int first = 1;
+	u32 shpc_cap_offset, shpc_base_offset;
+	u32 tempdword, slot_reg;
+	u16 vendor_id, device_id;
+	u8 i;
+
+	DBG_ENTER_ROUTINE
+
+	spin_lock_init(&amp;list_lock);
+	php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+
+	if (!php_ctlr) {	/* allocate controller state data */
+		err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
+		goto abort;
+	}
+
+	memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
+
+	php_ctlr-&gt;pci_dev = pdev;	/* save pci_dev in context */
+
+	rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &amp;vendor_id);
+	dbg("%s: Vendor ID: %x\n",__FUNCTION__, vendor_id);
+	if (rc) {
+		err("%s: unable to read PCI configuration data\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	rc = pci_read_config_word(pdev, PCI_DEVICE_ID, &amp;device_id);
+	dbg("%s: Device ID: %x\n",__FUNCTION__, device_id);
+	if (rc) {
+		err("%s: unable to read PCI configuration data\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	if ((vendor_id == PCI_VENDOR_ID_AMD) || (device_id == PCI_DEVICE_ID_AMD_GOLAM_7450)) {
+		shpc_base_offset = 0;  /* amd shpc driver doesn't use this; assume 0 */
+	} else {
+		if ((shpc_cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC)) == 0) {
+			err("%s : shpc_cap_offset == 0\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+	
+		rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset + DWORD_SELECT , BASE_OFFSET);
+		if (rc) {
+			err("%s : pci_word_config_byte failed\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+	
+		rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &amp;shpc_base_offset);
+		if (rc) {
+			err("%s : pci_read_config_dword failed\n", __FUNCTION__);
+			goto abort_free_ctlr;
+		}
+
+		for (i = 0; i &lt;= 14; i++) {
+			rc = pci_write_config_byte(pdev, (u8)shpc_cap_offset +  DWORD_SELECT , i);
+			if (rc) {
+				err("%s : pci_word_config_byte failed\n", __FUNCTION__);
+				goto abort_free_ctlr;
+			}
+	
+			rc = pci_read_config_dword(pdev, (u8)shpc_cap_offset + DWORD_DATA, &amp;tempdword);
+			if (rc) {
+				err("%s : pci_read_config_dword failed\n", __FUNCTION__);
+				goto abort_free_ctlr;
+			}
+			dbg("%s: offset %d: tempdword %x\n", __FUNCTION__,i, tempdword);
+		}
+	}
+
+	if (first) {
+		spin_lock_init(&amp;hpc_event_lock);
+		first = 0;
+	}
+
+	dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev-&gt;bus-&gt;number, PCI_SLOT(pdev-&gt;devfn), 
+		PCI_FUNC(pdev-&gt;devfn), pdev-&gt;irq);
+	for ( rc = 0; rc &lt; DEVICE_COUNT_RESOURCE; rc++)
+		if (pci_resource_len(pdev, rc) &gt; 0)
+			dbg("pci resource[%d] start=0x%lx(len=0x%lx), shpc_base_offset %x\n", rc,
+				pci_resource_start(pdev, rc), pci_resource_len(pdev, rc), shpc_base_offset);
+
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev-&gt;vendor, pdev-&gt;device, pdev-&gt;subsystem_vendor, 
+		pdev-&gt;subsystem_device);
+
+	if (!request_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0), MY_NAME)) {
+		err("%s: cannot reserve MMIO region\n", __FUNCTION__);
+		goto abort_free_ctlr;
+	}
+
+	php_ctlr-&gt;creg = (struct ctrl_reg *)
+		ioremap(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
+	if (!php_ctlr-&gt;creg) {
+		err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__, pci_resource_len(pdev, 0), 
+			pci_resource_start(pdev, 0) + shpc_base_offset);
+		release_mem_region(pci_resource_start(pdev, 0) + shpc_base_offset, pci_resource_len(pdev, 0));
+		goto abort_free_ctlr;
+	}
+	dbg("%s: php_ctlr-&gt;creg %p\n", __FUNCTION__, php_ctlr-&gt;creg);
+	dbg("%s: physical addr %p\n", __FUNCTION__, (void*)pci_resource_start(pdev, 0));
+
+	init_MUTEX(&amp;ctrl-&gt;crit_sect);
+	/* Setup wait queue */
+	init_waitqueue_head(&amp;ctrl-&gt;queue);
+
+	/* Find the IRQ */
+	php_ctlr-&gt;irq = pdev-&gt;irq;
+	dbg("HPC interrupt = %d\n", php_ctlr-&gt;irq);
+
+	/* Save interrupt callback info */
+	php_ctlr-&gt;attention_button_callback = attention_button_callback;
+	php_ctlr-&gt;switch_change_callback = switch_change_callback;
+	php_ctlr-&gt;presence_change_callback = presence_change_callback;
+	php_ctlr-&gt;power_fault_callback = power_fault_callback;
+	php_ctlr-&gt;callback_instance_id = instance_id;
+
+	/* Return PCI Controller Info */
+	php_ctlr-&gt;slot_device_offset = (readl(php_ctlr-&gt;creg + SLOT_CONFIG) &amp; FIRST_DEV_NUM ) &gt;&gt; 8;
+	php_ctlr-&gt;num_slots = readl(php_ctlr-&gt;creg + SLOT_CONFIG) &amp; SLOT_NUM;
+	dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr-&gt;slot_device_offset);
+	dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr-&gt;num_slots);
+
+	/* Mask Global Interrupt Mask &amp; Command Complete Interrupt Mask */
+	tempdword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	tempdword = 0x0003000f;   
+	writel(tempdword, php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+	tempdword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+	dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+
+	/* Mask the MRL sensor SERR Mask of individual slot in
+	 * Slot SERR-INT Mask &amp; clear all the existing event if any
+	 */
+	for (hp_slot = 0; hp_slot &lt; php_ctlr-&gt;num_slots; hp_slot++) {
+		slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*hp_slot );
+		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
+			hp_slot, slot_reg);
+		tempdword = 0xffffffff;  
+		writel(tempdword, php_ctlr-&gt;creg + SLOT1 + (4*hp_slot));
+	}
+	
+	if (shpchp_poll_mode)  {/* Install interrupt polling code */
+		/* Install and start the interrupt polling timer */
+		init_timer(&amp;php_ctlr-&gt;int_poll_timer);
+		start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+	} else {
+		/* Installs the interrupt handler */
+#ifdef CONFIG_PCI_USE_VECTOR 
+		rc = pci_enable_msi(pdev);
+		if (rc) {
+			err("Can't get msi for the hotplug controller\n");
+			dbg("%s: rc = %x\n", __FUNCTION__, rc);
+			goto abort_free_ctlr;
+		}
+		php_ctlr-&gt;irq = pdev-&gt;irq;
+#endif
+		
+		rc = request_irq(php_ctlr-&gt;irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+		dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr-&gt;irq, ctlr_seq_num, rc);
+		if (rc) {
+			err("Can't get irq %d for the hotplug controller\n", php_ctlr-&gt;irq);
+			goto abort_free_ctlr;
+		}
+		/* Execute OSHP method here */
+	}
+	dbg("%s: Before adding HPC to HPC list\n", __FUNCTION__);
+
+	/*  Add this HPC instance into the HPC list */
+	spin_lock(&amp;list_lock);
+	if (php_ctlr_list_head == 0) {
+		php_ctlr_list_head = php_ctlr;
+		p = php_ctlr_list_head;
+		p-&gt;pnext = 0;
+	} else {
+		p = php_ctlr_list_head;
+
+		while (p-&gt;pnext)
+			p = p-&gt;pnext;
+
+		p-&gt;pnext = php_ctlr;
+	}
+	spin_unlock(&amp;list_lock);
+
+
+	ctlr_seq_num++;
+	ctrl-&gt;hpc_ctlr_handle = php_ctlr;
+	ctrl-&gt;hpc_ops = &amp;shpchp_hpc_ops;
+
+	for (hp_slot = 0; hp_slot &lt; php_ctlr-&gt;num_slots; hp_slot++) {
+		slot_reg = readl(php_ctlr-&gt;creg + SLOT1 + 4*hp_slot );
+		dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
+			hp_slot, slot_reg);
+		tempdword = 0xe01fffff;  
+		writel(tempdword, php_ctlr-&gt;creg + SLOT1 + (4*hp_slot));
+	}
+	if (!shpchp_poll_mode) {
+		/* Unmask all general input interrupts and SERR */
+		tempdword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+		tempdword = 0x0000000a;
+		writel(tempdword, php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+		tempdword = readl(php_ctlr-&gt;creg + SERR_INTR_ENABLE);
+		dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
+	}
+
+	dbg("%s: Leaving shpc_init\n", __FUNCTION__);
+	DBG_LEAVE_ROUTINE
+	return 0;
+
+	/* We end up here for the many possible ways to fail this API.  */
+abort_free_ctlr:
+	kfree(php_ctlr);
+abort:
+	DBG_LEAVE_ROUTINE
+	return -1;
+}
diff -puN /dev/null drivers/pci/hotplug/shpchp_pci.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchp_pci.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,821 @@
+/*
+ * Standard Hot Plug Controller Driver
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/pci.h&gt;
+#include "../pci.h"
+#include "shpchp.h"
+#ifndef CONFIG_IA64
+#include "../../../arch/i386/pci/pci.h"    /* horrible hack showing how processor dependant we are... */
+#endif
+
+int shpchp_configure_device (struct controller* ctrl, struct pci_func* func)  
+{
+	unsigned char bus;
+	struct pci_bus *child;
+	int num;
+
+	if (func-&gt;pci_dev == NULL)
+		func-&gt;pci_dev = pci_find_slot(func-&gt;bus, PCI_DEVFN(func-&gt;device, func-&gt;function));
+
+	/* Still NULL ? Well then scan for it ! */
+	if (func-&gt;pci_dev == NULL) {
+		num = pci_scan_slot(ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(func-&gt;device, func-&gt;function));
+		if (num)
+			dbg("%s: subordiante %p number %x\n", __FUNCTION__, ctrl-&gt;pci_dev-&gt;subordinate,
+				ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+			pci_bus_add_devices(ctrl-&gt;pci_dev-&gt;subordinate);		
+		
+		func-&gt;pci_dev = pci_find_slot(func-&gt;bus, PCI_DEVFN(func-&gt;device, func-&gt;function));
+		if (func-&gt;pci_dev == NULL) {
+			dbg("ERROR: pci_dev still null\n");
+			return 0;
+		}
+	}
+
+	if (func-&gt;pci_dev-&gt;hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		pci_read_config_byte(func-&gt;pci_dev, PCI_SECONDARY_BUS, &amp;bus);
+		child = (struct pci_bus*) pci_add_new_bus(func-&gt;pci_dev-&gt;bus, (func-&gt;pci_dev), bus);
+		pci_do_scan_bus(child);
+
+	}
+
+	return 0;
+}
+
+
+int shpchp_unconfigure_device(struct pci_func* func) 
+{
+	int rc = 0;
+	int j;
+	
+	dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+
+	for (j=0; j&lt;8 ; j++) {
+		struct pci_dev* temp = pci_find_slot(func-&gt;bus, (func-&gt;device &lt;&lt; 3) | j);
+		if (temp) {
+			pci_remove_bus_device(temp);
+		}
+	}
+	return rc;
+}
+
+/*
+ * shpchp_set_irq
+ *
+ * @bus_num: bus number of PCI device
+ * @dev_num: device number of PCI device
+ * @slot: pointer to u8 where slot number will be returned
+ */
+int shpchp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
+{
+#if !defined(CONFIG_X86_IO_APIC) &amp;&amp; !defined(CONFIG_X86_64)
+	int rc;
+	u16 temp_word;
+	struct pci_dev fakedev;
+	struct pci_bus fakebus;
+
+	fakedev.devfn = dev_num &lt;&lt; 3;
+	fakedev.bus = &amp;fakebus;
+	fakebus.number = bus_num;
+	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
+	rc = pcibios_set_irq_routing(&amp;fakedev, int_pin - 0x0a, irq_num);
+	dbg("%s: rc %d\n", __FUNCTION__, rc);
+	if (!rc)
+		return !rc;
+
+	/* set the Edge Level Control Register (ELCR) */
+	temp_word = inb(0x4d0);
+	temp_word |= inb(0x4d1) &lt;&lt; 8;
+
+	temp_word |= 0x01 &lt;&lt; irq_num;
+
+	/* This should only be for x86 as it sets the Edge Level Control Register */
+	outb((u8) (temp_word &amp; 0xFF), 0x4d0);
+	outb((u8) ((temp_word &amp; 0xFF00) &gt;&gt; 8), 0x4d1);
+#endif
+	return 0;
+}
+
+/* More PCI configuration routines; this time centered around hotplug controller */
+
+
+/*
+ * shpchp_save_config
+ *
+ * Reads configuration for all slots in a PCI bus and saves info.
+ *
+ * Note:  For non-hot plug busses, the slot # saved is the device #
+ *
+ * returns 0 if success
+ */
+int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	struct pci_func *new_slot;
+	int sub_bus;
+	int FirstSupported;
+	int LastSupported;
+	int max_functions;
+	int function;
+	u8 DevError;
+	int device = 0;
+	int cloop = 0;
+	int stop_it;
+	int index;
+	int is_hot_plug = num_ctlr_slots || first_device_num;
+	struct pci_bus lpci_bus, *pci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num);
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+
+	dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__, num_ctlr_slots, first_device_num);
+
+	/*   Decide which slots are supported */
+	if (is_hot_plug) {
+		/*********************************
+		 *  is_hot_plug is the slot mask
+		 *********************************/
+		FirstSupported = first_device_num;
+		LastSupported = FirstSupported + num_ctlr_slots - 1;
+	} else {
+		FirstSupported = 0;
+		LastSupported = 0x1F;
+	}
+
+	dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported, LastSupported);
+
+	/*   Save PCI configuration space for all devices in supported slots */
+	pci_bus-&gt;number = busnumber;
+	for (device = FirstSupported; device &lt;= LastSupported; device++) {
+		ID = 0xFFFFFFFF;
+		rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &amp;ID);
+
+		if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), 0x0B, &amp;class_code);
+			if (rc)
+				return rc;
+
+			rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &amp;header_type);
+			if (rc)
+				return rc;
+
+			dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+
+			/* If multi-function device, set max_functions to 8 */
+			if (header_type &amp; 0x80)
+				max_functions = 8;
+			else
+				max_functions = 1;
+
+			function = 0;
+
+			do {
+				DevError = 0;
+
+				if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
+					/* Recurse the subordinate bus
+					 * get the subordinate bus number
+					 */
+					rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 
+						PCI_SECONDARY_BUS, &amp;secondary_bus);
+					if (rc) {
+						return rc;
+					} else {
+						sub_bus = (int) secondary_bus;
+
+						/* Save secondary bus cfg spc with this recursive call. */
+						rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
+						if (rc)
+							return rc;
+					}
+				}
+
+				index = 0;
+				new_slot = shpchp_slot_find(busnumber, device, index++);
+
+				dbg("new_slot = %p\n", new_slot);
+
+				while (new_slot &amp;&amp; (new_slot-&gt;function != (u8) function)) {
+					new_slot = shpchp_slot_find(busnumber, device, index++);
+					dbg("new_slot = %p\n", new_slot);
+				}
+				if (!new_slot) {
+					/* Setup slot structure. */
+					new_slot = shpchp_slot_create(busnumber);
+					dbg("new_slot = %p\n", new_slot);
+
+					if (new_slot == NULL)
+						return(1);
+				}
+
+				new_slot-&gt;bus = (u8) busnumber;
+				new_slot-&gt;device = (u8) device;
+				new_slot-&gt;function = (u8) function;
+				new_slot-&gt;is_a_board = 1;
+				new_slot-&gt;switch_save = 0x10;
+				/* In case of unsupported board */
+				new_slot-&gt;status = DevError;
+				new_slot-&gt;pci_dev = pci_find_slot(new_slot-&gt;bus, (new_slot-&gt;device &lt;&lt; 3) | new_slot-&gt;function);
+				dbg("new_slot-&gt;pci_dev = %p\n", new_slot-&gt;pci_dev);
+
+				for (cloop = 0; cloop &lt; 0x20; cloop++) {
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), 
+						cloop &lt;&lt; 2, (u32 *) &amp; (new_slot-&gt;config_space [cloop]));
+					/* dbg("new_slot-&gt;config_space[%x] = %x\n", cloop, new_slot-&gt;config_space[cloop]); */
+					if (rc)
+						return rc;
+				}
+
+				function++;
+
+				stop_it = 0;
+
+				/*  this loop skips to the next present function
+				 *  reading in Class Code and Header type.
+				 */
+
+				while ((function &lt; max_functions)&amp;&amp;(!stop_it)) {
+					rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &amp;ID);
+
+					if (ID == 0xFFFFFFFF) {  /* nothing there. */
+						function++;
+						dbg("Nothing there\n");
+					} else {  /* Something there */
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 
+							0x0B, &amp;class_code);
+						if (rc)
+							return rc;
+
+						rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, function), 
+							PCI_HEADER_TYPE, &amp;header_type);
+						if (rc)
+							return rc;
+
+						dbg("class_code = %x, header_type = %x\n", class_code, header_type);
+						stop_it++;
+					}
+				}
+
+			} while (function &lt; max_functions);
+			/* End of IF (device in slot?) */
+		} else if (is_hot_plug) {
+			/* Setup slot structure with entry for empty slot */
+			new_slot = shpchp_slot_create(busnumber);
+
+			if (new_slot == NULL) {
+				return(1);
+			}
+			dbg("new_slot = %p\n", new_slot);
+
+			new_slot-&gt;bus = (u8) busnumber;
+			new_slot-&gt;device = (u8) device;
+			new_slot-&gt;function = 0;
+			new_slot-&gt;is_a_board = 0;
+			new_slot-&gt;presence_save = 0;
+			new_slot-&gt;switch_save = 0;
+		}
+	}			/* End of FOR loop */
+
+	return(0);
+}
+
+
+/*
+ * shpchp_save_slot_config
+ *
+ * Saves configuration info for all PCI devices in a given slot
+ * including subordinate busses.
+ *
+ * returns 0 if success
+ */
+int shpchp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot)
+{
+	int rc;
+	u8 class_code;
+	u8 header_type;
+	u32 ID;
+	u8 secondary_bus;
+	int sub_bus;
+	int max_functions;
+	int function;
+	int cloop = 0;
+	int stop_it;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = new_slot-&gt;bus;
+
+	ID = 0xFFFFFFFF;
+
+	pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot-&gt;device, 0), PCI_VENDOR_ID, &amp;ID);
+
+	if (ID != 0xFFFFFFFF) {	  /*  device in slot */
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, 0), 0x0B, &amp;class_code);
+
+		pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, 0), PCI_HEADER_TYPE, &amp;header_type);
+
+		if (header_type &amp; 0x80)	/* Multi-function device */
+			max_functions = 8;
+		else
+			max_functions = 1;
+
+		function = 0;
+
+		do {
+			if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {	  /* PCI-PCI Bridge */
+				/*  Recurse the subordinate bus */
+				pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), 
+					PCI_SECONDARY_BUS, &amp;secondary_bus);
+
+				sub_bus = (int) secondary_bus;
+
+				/* Save the config headers for the secondary bus. */
+				rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
+
+				if (rc)
+					return(rc);
+
+			}	/* End of IF */
+
+			new_slot-&gt;status = 0;
+
+			for (cloop = 0; cloop &lt; 0x20; cloop++) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), 
+					cloop &lt;&lt; 2, (u32 *) &amp; (new_slot-&gt;config_space [cloop]));
+			}
+
+			function++;
+
+			stop_it = 0;
+
+			/*  this loop skips to the next present function
+			 *  reading in the Class Code and the Header type.
+			 */
+
+			while ((function &lt; max_functions) &amp;&amp; (!stop_it)) {
+				pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), PCI_VENDOR_ID, &amp;ID);
+
+				if (ID == 0xFFFFFFFF) {	 /* nothing there. */
+					function++;
+				} else {  /* Something there */
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), 0x0B, &amp;class_code);
+
+					pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot-&gt;device, function), PCI_HEADER_TYPE, 
+						&amp;header_type);
+
+					stop_it++;
+				}
+			}
+
+		} while (function &lt; max_functions);
+	}			/* End of IF (device in slot?) */
+	else {
+		return(2);
+	}
+
+	return(0);
+}
+
+
+/*
+ * shpchp_save_used_resources
+ *
+ * Stores used resource information for existing boards.  this is
+ * for boards that were in the system when this driver was loaded.
+ * this function is for hot plug ADD
+ *
+ * returns 0 if success
+ * if disable  == 1(DISABLE_CARD),
+ *  it loops for all functions of the slot and disables them.
+ * else, it just get resources of the function and return.
+ */
+int shpchp_save_used_resources (struct controller *ctrl, struct pci_func *func, int disable)
+{
+	u8 cloop;
+	u8 header_type;
+	u8 secondary_bus;
+	u8 temp_byte;
+	u16 command;
+	u16 save_command;
+	u16 w_base, w_length;
+	u32 temp_register;
+	u32 save_base;
+	u32 base, length;
+	u64 base64 = 0;
+	int index = 0;
+	unsigned int devfn;
+	struct pci_resource *mem_node = NULL;
+	struct pci_resource *p_mem_node = NULL;
+	struct pci_resource *t_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	struct pci_bus lpci_bus, *pci_bus;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_dev-&gt;subordinate, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+
+	if (disable)
+		func = shpchp_slot_find(func-&gt;bus, func-&gt;device, index++);
+
+	while ((func != NULL) &amp;&amp; func-&gt;is_a_board) {
+		pci_bus-&gt;number = func-&gt;bus;
+		devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+		/* Save the command register */
+		pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &amp;save_command);
+
+		if (disable) {
+			/* disable card */
+			command = 0x00;
+			pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+		}
+
+		/* Check for Bridge */
+		pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &amp;header_type);
+
+		if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
+			dbg("Save_used_res of PCI bridge b:d=0x%x:%x, sc=0x%x\n", func-&gt;bus, func-&gt;device, save_command);
+			if (disable) {
+				/* Clear Bridge Control Register */
+				command = 0x00;
+				pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command);
+			}
+
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &amp;secondary_bus);
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &amp;temp_byte);
+
+			bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node-&gt;base = (ulong)secondary_bus;
+			bus_node-&gt;length = (ulong)(temp_byte - secondary_bus + 1);
+
+			bus_node-&gt;next = func-&gt;bus_head;
+			func-&gt;bus_head = bus_node;
+
+			/* Save IO base and Limit registers */
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &amp;temp_byte);
+			base = temp_byte;
+			pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &amp;temp_byte);
+			length = temp_byte;
+
+			if ((base &lt;= length) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_IO))) {
+				io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!io_node)
+					return -ENOMEM;
+
+				io_node-&gt;base = (ulong)(base &amp; PCI_IO_RANGE_MASK) &lt;&lt; 8;
+				io_node-&gt;length = (ulong)(length - base + 0x10) &lt;&lt; 8;
+
+				io_node-&gt;next = func-&gt;io_head;
+				func-&gt;io_head = io_node;
+			}
+
+			/* Save memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &amp;w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &amp;w_length);
+
+			if ((w_base &lt;= w_length) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_MEMORY))) {
+				mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!mem_node)
+					return -ENOMEM;
+
+				mem_node-&gt;base = (ulong)w_base &lt;&lt; 16;
+				mem_node-&gt;length = (ulong)(w_length - w_base + 0x10) &lt;&lt; 16;
+
+				mem_node-&gt;next = func-&gt;mem_head;
+				func-&gt;mem_head = mem_node;
+			}
+			/* Save prefetchable memory base and Limit registers */
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &amp;w_base);
+			pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &amp;w_length);
+
+			if ((w_base &lt;= w_length) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_MEMORY))) {
+				p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+				if (!p_mem_node)
+					return -ENOMEM;
+
+				p_mem_node-&gt;base = (ulong)w_base &lt;&lt; 16;
+				p_mem_node-&gt;length = (ulong)(w_length - w_base + 0x10) &lt;&lt; 16;
+
+				p_mem_node-&gt;next = func-&gt;p_mem_head;
+				func-&gt;p_mem_head = p_mem_node;
+			}
+		} else if ((header_type &amp; 0x7F) == PCI_HEADER_TYPE_NORMAL) {
+			dbg("Save_used_res of PCI adapter b:d=0x%x:%x, sc=0x%x\n", func-&gt;bus, func-&gt;device, save_command);
+
+			/* Figure out IO and memory base lengths */
+			for (cloop = PCI_BASE_ADDRESS_0; cloop &lt;= PCI_BASE_ADDRESS_5; cloop += 4) {
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &amp;save_base);
+
+				temp_register = 0xFFFFFFFF;
+				pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register);
+				pci_bus_read_config_dword (pci_bus, devfn, cloop, &amp;temp_register);
+
+				if (!disable) {
+					pci_bus_write_config_dword (pci_bus, devfn, cloop, save_base);
+				}
+
+				if (!temp_register)
+					continue;
+
+				base = temp_register;
+
+				if ((base &amp; PCI_BASE_ADDRESS_SPACE_IO) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_IO))) {
+					/* IO base */
+					/* set temp_register = amount of IO space requested */
+					base = base &amp; 0xFFFFFFFCL;
+					base = (~base) + 1;
+
+					io_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!io_node)
+						return -ENOMEM;
+
+					io_node-&gt;base = (ulong)save_base &amp; PCI_BASE_ADDRESS_IO_MASK;
+					io_node-&gt;length = (ulong)base;
+					dbg("sur adapter: IO bar=0x%x(length=0x%x)\n", io_node-&gt;base, io_node-&gt;length);
+
+					io_node-&gt;next = func-&gt;io_head;
+					func-&gt;io_head = io_node;
+				} else {  /* map Memory */
+					int prefetchable = 1;
+					/* struct pci_resources **res_node; */
+					char *res_type_str = "PMEM";
+					u32 temp_register2;
+
+					t_mem_node = (struct pci_resource *) kmalloc(sizeof (struct pci_resource), GFP_KERNEL);
+					if (!t_mem_node)
+						return -ENOMEM;
+
+					if (!(base &amp; PCI_BASE_ADDRESS_MEM_PREFETCH) &amp;&amp; (!disable || (save_command &amp; PCI_COMMAND_MEMORY))) {
+						prefetchable = 0;
+						mem_node = t_mem_node;
+						res_type_str++;
+					} else
+						p_mem_node = t_mem_node;
+
+					base = base &amp; 0xFFFFFFF0L;
+					base = (~base) + 1;
+
+					switch (temp_register &amp; PCI_BASE_ADDRESS_MEM_TYPE_MASK) {
+					case PCI_BASE_ADDRESS_MEM_TYPE_32:
+						if (prefetchable) {
+							p_mem_node-&gt;base = (ulong)save_base &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node-&gt;length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, 
+								p_mem_node-&gt;base, p_mem_node-&gt;length);
+
+							p_mem_node-&gt;next = func-&gt;p_mem_head;
+							func-&gt;p_mem_head = p_mem_node;
+						} else {
+							mem_node-&gt;base = (ulong)save_base &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node-&gt;length = (ulong)base;
+							dbg("sur adapter: 32 %s bar=0x%x(length=0x%x)\n", res_type_str, 
+								mem_node-&gt;base, mem_node-&gt;length);
+
+							mem_node-&gt;next = func-&gt;mem_head;
+							func-&gt;mem_head = mem_node;
+						}
+						break;
+					case PCI_BASE_ADDRESS_MEM_TYPE_64:
+						pci_bus_read_config_dword(pci_bus, devfn, cloop+4, &amp;temp_register2);
+						base64 = temp_register2;
+						base64 = (base64 &lt;&lt; 32) | save_base;
+
+						if (temp_register2) {
+							dbg("sur adapter: 64 %s high dword of base64(0x%x:%x) masked to 0\n", 
+								res_type_str, temp_register2, (u32)base64);
+							base64 &amp;= 0x00000000FFFFFFFFL;
+						}
+
+						if (prefetchable) {
+							p_mem_node-&gt;base = base64 &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							p_mem_node-&gt;length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, 
+								p_mem_node-&gt;base, p_mem_node-&gt;length);
+
+							p_mem_node-&gt;next = func-&gt;p_mem_head;
+							func-&gt;p_mem_head = p_mem_node;
+						} else {
+							mem_node-&gt;base = base64 &amp; PCI_BASE_ADDRESS_MEM_MASK;
+							mem_node-&gt;length = base;
+							dbg("sur adapter: 64 %s base=0x%x(len=0x%x)\n", res_type_str, 
+								mem_node-&gt;base, mem_node-&gt;length);
+
+							mem_node-&gt;next = func-&gt;mem_head;
+							func-&gt;mem_head = mem_node;
+						}
+						cloop += 4;
+						break;
+					default:
+						dbg("asur: reserved BAR type=0x%x\n", temp_register);
+						break;
+					}
+				} 
+			}	/* End of base register loop */
+		} else {	/* Some other unknown header type */
+			dbg("Save_used_res of PCI unknown type b:d=0x%x:%x. skip.\n", func-&gt;bus, func-&gt;device);
+		}
+
+		/* find the next device in this slot */
+		if (!disable)
+			break;
+		func = shpchp_slot_find(func-&gt;bus, func-&gt;device, index++);
+	}
+
+	return(0);
+}
+
+
+/*
+ * shpchp_return_board_resources
+ *
+ * this routine returns all resources allocated to a board to
+ * the available pool.
+ *
+ * returns 0 if success
+ */
+int shpchp_return_board_resources(struct pci_func * func, struct resource_lists * resources)
+{
+	int rc = 0;
+	struct pci_resource *node;
+	struct pci_resource *t_node;
+	dbg("%s\n", __FUNCTION__);
+
+	if (!func)
+		return(1);
+
+	node = func-&gt;io_head;
+	func-&gt;io_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;io_head), node);
+		node = t_node;
+	}
+
+	node = func-&gt;mem_head;
+	func-&gt;mem_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;mem_head), node);
+		node = t_node;
+	}
+
+	node = func-&gt;p_mem_head;
+	func-&gt;p_mem_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;p_mem_head), node);
+		node = t_node;
+	}
+
+	node = func-&gt;bus_head;
+	func-&gt;bus_head = NULL;
+	while (node) {
+		t_node = node-&gt;next;
+		return_resource(&amp;(resources-&gt;bus_head), node);
+		node = t_node;
+	}
+
+	rc |= shpchp_resource_sort_and_combine(&amp;(resources-&gt;mem_head));
+	rc |= shpchp_resource_sort_and_combine(&amp;(resources-&gt;p_mem_head));
+	rc |= shpchp_resource_sort_and_combine(&amp;(resources-&gt;io_head));
+	rc |= shpchp_resource_sort_and_combine(&amp;(resources-&gt;bus_head));
+
+	return(rc);
+}
+
+
+/*
+ * shpchp_destroy_resource_list
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void shpchp_destroy_resource_list (struct resource_lists * resources)
+{
+	struct pci_resource *res, *tres;
+
+	res = resources-&gt;io_head;
+	resources-&gt;io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = resources-&gt;mem_head;
+	resources-&gt;mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = resources-&gt;p_mem_head;
+	resources-&gt;p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = resources-&gt;bus_head;
+	resources-&gt;bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+}
+
+
+/*
+ * shpchp_destroy_board_resources
+ *
+ * Puts node back in the resource list pointed to by head
+ */
+void shpchp_destroy_board_resources (struct pci_func * func)
+{
+	struct pci_resource *res, *tres;
+
+	res = func-&gt;io_head;
+	func-&gt;io_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = func-&gt;mem_head;
+	func-&gt;mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = func-&gt;p_mem_head;
+	func-&gt;p_mem_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+
+	res = func-&gt;bus_head;
+	func-&gt;bus_head = NULL;
+
+	while (res) {
+		tres = res;
+		res = res-&gt;next;
+		kfree(tres);
+	}
+}
+
diff -puN /dev/null drivers/pci/hotplug/shpchprm_acpi.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchprm_acpi.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,1694 @@
+/*
+ * SHPCHPRM ACPI: PHP Resource Manager for ACPI platform
+ *
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;linux/acpi.h&gt;
+#include &lt;linux/efi.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#include &lt;asm/system.h&gt;
+#ifdef	CONFIG_IA64
+#include &lt;asm/iosapic.h&gt;
+#endif
+#include &lt;acpi/acpi.h&gt;
+#include &lt;acpi/acpi_bus.h&gt;
+#include &lt;acpi/actypes.h&gt;
+#include "shpchp.h"
+#include "shpchprm.h"
+
+#define	PCI_MAX_BUS		0x100
+#define	ACPI_STA_DEVICE_PRESENT	0x01
+
+#define	METHOD_NAME__SUN	"_SUN"
+#define	METHOD_NAME__HPP	"_HPP"
+#define	METHOD_NAME_OSHP	"OSHP"
+
+#define	PHP_RES_BUS		0xA0
+#define	PHP_RES_IO		0xA1
+#define	PHP_RES_MEM		0xA2
+#define	PHP_RES_PMEM		0xA3
+
+#define	BRIDGE_TYPE_P2P		0x00
+#define	BRIDGE_TYPE_HOST	0x01
+
+/* this should go to drivers/acpi/include/ */
+struct acpi__hpp {
+	u8	cache_line_size;
+	u8	latency_timer;
+	u8	enable_serr;
+	u8	enable_perr;
+};
+
+struct acpi_php_slot {
+	struct acpi_php_slot	*next;
+	struct acpi_bridge	*bridge;
+	acpi_handle		handle;
+	int	seg;
+	int	bus;
+	int	dev;
+	int	fun;
+	u32	sun;
+	struct pci_resource *mem_head;
+	struct pci_resource *p_mem_head;
+	struct pci_resource *io_head;
+	struct pci_resource *bus_head;
+	void	*slot_ops;	/* _STA, _EJx, etc */
+	struct slot *slot;
+};		/* per func */
+
+struct acpi_bridge {
+	struct acpi_bridge	*parent;
+	struct acpi_bridge	*next;
+	struct acpi_bridge	*child;
+	acpi_handle	handle;
+	int seg;
+	int pbus;				/* pdev-&gt;bus-&gt;number		*/
+	int pdevice;				/* PCI_SLOT(pdev-&gt;devfn)	*/
+	int pfunction;				/* PCI_DEVFN(pdev-&gt;devfn)	*/
+	int bus;				/* pdev-&gt;subordinate-&gt;number	*/
+	struct acpi__hpp		*_hpp;
+	struct acpi_php_slot	*slots;
+	struct pci_resource 	*tmem_head;	/* total from crs	*/
+	struct pci_resource 	*tp_mem_head;	/* total from crs	*/
+	struct pci_resource 	*tio_head;	/* total from crs	*/
+	struct pci_resource 	*tbus_head;	/* total from crs	*/
+	struct pci_resource 	*mem_head;	/* available	*/
+	struct pci_resource 	*p_mem_head;	/* available	*/
+	struct pci_resource 	*io_head;	/* available	*/
+	struct pci_resource 	*bus_head;	/* available	*/
+	int scanned;
+	int type;
+};
+
+static struct acpi_bridge *acpi_bridges_head;
+
+static u8 * acpi_path_name( acpi_handle	handle)
+{
+	acpi_status		status;
+	static u8	path_name[ACPI_PATHNAME_MAX];
+	struct acpi_buffer		ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+	memset(path_name, 0, sizeof (path_name));
+	status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &amp;ret_buf);
+
+	if (ACPI_FAILURE(status))
+		return NULL;
+	else
+		return path_name;	
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab);
+static void acpi_run_oshp ( struct acpi_bridge	*ab);
+
+static int acpi_add_slot_to_php_slots(
+	struct acpi_bridge	*ab,
+	int				bus_num,
+	acpi_handle		handle,
+	u32				adr,
+	u32				sun
+	)
+{
+	struct acpi_php_slot	*aps;
+	static long	samesun = -1;
+
+	aps = (struct acpi_php_slot *) kmalloc (sizeof(struct acpi_php_slot), GFP_KERNEL);
+	if (!aps) {
+		err ("acpi_shpchprm: alloc for aps fail\n");
+		return -1;
+	}
+	memset(aps, 0, sizeof(struct acpi_php_slot));
+
+	aps-&gt;handle = handle;
+	aps-&gt;bus = bus_num;
+	aps-&gt;dev = (adr &gt;&gt; 16) &amp; 0xffff;
+	aps-&gt;fun = adr &amp; 0xffff;
+	aps-&gt;sun = sun;
+
+	aps-&gt;next = ab-&gt;slots;	/* cling to the bridge */
+	aps-&gt;bridge = ab;
+	ab-&gt;slots = aps;
+
+	ab-&gt;scanned += 1;
+	if (!ab-&gt;_hpp)
+		acpi_get__hpp(ab);
+
+	acpi_run_oshp(ab);
+
+	if (sun != samesun) {
+		info("acpi_shpchprm:   Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", aps-&gt;sun, ab-&gt;seg, 
+			aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+		samesun = sun;
+	}
+	return 0;
+}
+
+static void acpi_get__hpp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			nui[4];
+	struct acpi_buffer	ret_buf = { 0, NULL};
+	union acpi_object	*ext_obj, *package;
+	u8			*path_name = acpi_path_name(ab-&gt;handle);
+	int			i, len = 0;
+
+	/* get _hpp */
+	status = acpi_evaluate_object(ab-&gt;handle, METHOD_NAME__HPP, NULL, &amp;ret_buf);
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		ret_buf.pointer = kmalloc (ret_buf.length, GFP_KERNEL);
+		if (!ret_buf.pointer) {
+			err ("acpi_shpchprm:%s alloc for _HPP fail\n", path_name);
+			return;
+		}
+		status = acpi_evaluate_object(ab-&gt;handle, METHOD_NAME__HPP, NULL, &amp;ret_buf);
+		if (ACPI_SUCCESS(status))
+			break;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_shpchprm:%s _HPP fail=0x%x\n", path_name, status);
+			return;
+		}
+	}
+
+	ext_obj = (union acpi_object *) ret_buf.pointer;
+	if (ext_obj-&gt;type != ACPI_TYPE_PACKAGE) {
+		err ("acpi_shpchprm:%s _HPP obj not a package\n", path_name);
+		goto free_and_return;
+	}
+
+	len = ext_obj-&gt;package.count;
+	package = (union acpi_object *) ret_buf.pointer;
+	for ( i = 0; (i &lt; len) || (i &lt; 4); i++) {
+		ext_obj = (union acpi_object *) &amp;package-&gt;package.elements[i];
+		switch (ext_obj-&gt;type) {
+		case ACPI_TYPE_INTEGER:
+			nui[i] = (u8)ext_obj-&gt;integer.value;
+			break;
+		default:
+			err ("acpi_shpchprm:%s _HPP obj type incorrect\n", path_name);
+			goto free_and_return;
+		}
+	}
+
+	ab-&gt;_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	memset(ab-&gt;_hpp, 0, sizeof(struct acpi__hpp));
+
+	ab-&gt;_hpp-&gt;cache_line_size	= nui[0];
+	ab-&gt;_hpp-&gt;latency_timer		= nui[1];
+	ab-&gt;_hpp-&gt;enable_serr		= nui[2];
+	ab-&gt;_hpp-&gt;enable_perr		= nui[3];
+
+	dbg("  _HPP: cache_line_size=0x%x\n", ab-&gt;_hpp-&gt;cache_line_size);
+	dbg("  _HPP: latency timer  =0x%x\n", ab-&gt;_hpp-&gt;latency_timer);
+	dbg("  _HPP: enable SERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_serr);
+	dbg("  _HPP: enable PERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_perr);
+
+free_and_return:
+	kfree(ret_buf.pointer);
+}
+
+static void acpi_run_oshp ( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(ab-&gt;handle);
+	struct acpi_buffer	ret_buf = { 0, NULL};
+
+	/* run OSHP */
+	status = acpi_evaluate_object(ab-&gt;handle, METHOD_NAME_OSHP, NULL, &amp;ret_buf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status);
+	} else
+		dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status);
+	return;
+}
+
+static acpi_status acpi_evaluate_crs(
+	acpi_handle		handle,
+	struct acpi_resource	**retbuf
+	)
+{
+	acpi_status		status;
+	struct acpi_buffer		crsbuf;
+	u8			*path_name = acpi_path_name(handle);
+
+	crsbuf.length  = 0;
+	crsbuf.pointer = NULL;
+
+	status = acpi_get_current_resources (handle, &amp;crsbuf);
+
+	switch (status) {
+	case AE_BUFFER_OVERFLOW:
+		break;		/* found */
+	case AE_NOT_FOUND:
+		dbg("acpi_shpchprm:%s _CRS not found\n", path_name);
+		return status;
+	default:
+		err ("acpi_shpchprm:%s _CRS fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	crsbuf.pointer = kmalloc (crsbuf.length, GFP_KERNEL);
+	if (!crsbuf.pointer) {
+		err ("acpi_shpchprm: alloc %ld bytes for %s _CRS fail\n", (ulong)crsbuf.length, path_name);
+		return AE_NO_MEMORY;
+	}
+
+	status = acpi_get_current_resources (handle, &amp;crsbuf);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm: %s _CRS fail=0x%x.\n", path_name, status);
+		kfree(crsbuf.pointer);
+		return status;
+	}
+
+	*retbuf = crsbuf.pointer;
+
+	return status;
+}
+
+static void free_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res, *next;
+
+	for (res = aprh; res; res = next) {
+		next = res-&gt;next;
+		kfree(res);
+	}
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res-&gt;next)
+		dbg("        base= 0x%x length= 0x%x\n", res-&gt;base, res-&gt;length);
+}
+
+static void print_slot_resources( struct acpi_php_slot	*aps)
+{
+	if (aps-&gt;bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (aps-&gt;bus_head);
+	}
+
+	if (aps-&gt;io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (aps-&gt;io_head);
+	}
+
+	if (aps-&gt;mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (aps-&gt;mem_head);
+	}
+
+	if (aps-&gt;p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (aps-&gt;p_mem_head);
+	}
+}
+
+static void print_pci_resources( struct acpi_bridge	*ab)
+{
+	if (ab-&gt;tbus_head) {
+		dbg("    Total BUS Resources:\n");
+		print_pci_resource (ab-&gt;tbus_head);
+	}
+	if (ab-&gt;bus_head) {
+		dbg("    BUS Resources:\n");
+		print_pci_resource (ab-&gt;bus_head);
+	}
+
+	if (ab-&gt;tio_head) {
+		dbg("    Total IO Resources:\n");
+		print_pci_resource (ab-&gt;tio_head);
+	}
+	if (ab-&gt;io_head) {
+		dbg("    IO Resources:\n");
+		print_pci_resource (ab-&gt;io_head);
+	}
+
+	if (ab-&gt;tmem_head) {
+		dbg("    Total MEM Resources:\n");
+		print_pci_resource (ab-&gt;tmem_head);
+	}
+	if (ab-&gt;mem_head) {
+		dbg("    MEM Resources:\n");
+		print_pci_resource (ab-&gt;mem_head);
+	}
+
+	if (ab-&gt;tp_mem_head) {
+		dbg("    Total PMEM Resources:\n");
+		print_pci_resource (ab-&gt;tp_mem_head);
+	}
+	if (ab-&gt;p_mem_head) {
+		dbg("    PMEM Resources:\n");
+		print_pci_resource (ab-&gt;p_mem_head);
+	}
+	if (ab-&gt;_hpp) {
+		dbg("    _HPP: cache_line_size=0x%x\n", ab-&gt;_hpp-&gt;cache_line_size);
+		dbg("    _HPP: latency timer  =0x%x\n", ab-&gt;_hpp-&gt;latency_timer);
+		dbg("    _HPP: enable SERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_serr);
+		dbg("    _HPP: enable PERR    =0x%x\n", ab-&gt;_hpp-&gt;enable_perr);
+	}
+}
+
+static int shpchprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	shpchp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if (res-&gt;base &gt; base)
+			continue;
+
+		if ((res-&gt;base + res-&gt;length) &lt; (base + size))
+			continue;
+
+		if (res-&gt;base &lt; base) {
+			tbase = base;
+
+			if ((res-&gt;length - (tbase - res-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base;
+			split_node-&gt;length = tbase - res-&gt;base;
+			res-&gt;base = tbase;
+			res-&gt;length -= split_node-&gt;length;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (res-&gt;length &gt;= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base + size;
+			split_node-&gt;length = res-&gt;length - size;
+			res-&gt;length = size;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res-&gt;next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode-&gt;next != res)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = res-&gt;next;
+		}
+		res-&gt;next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+static int shpchprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res-&gt;next)
+		shpchprm_delete_resource(aprh, res-&gt;base, res-&gt;length);
+
+	return 0;
+}
+
+static int shpchprm_add_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if ((res-&gt;base + res-&gt;length) == base) {
+			res-&gt;length += size;
+			size = 0L;
+			break;
+		}
+		if (res-&gt;next == *aprh)
+			break;
+	}
+
+	if (size) {
+		res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+		if (!res) {
+			err ("acpi_shpchprm: alloc for res fail\n");
+			return -ENOMEM;
+		}
+		memset(res, 0, sizeof (struct pci_resource));
+
+		res-&gt;base = base;
+		res-&gt;length = size;
+		res-&gt;next = *aprh;
+		*aprh = res;
+	}
+
+	return 0;
+}
+
+static int shpchprm_add_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+	int	rc = 0;
+
+	for (res = this; res &amp;&amp; !rc; res = res-&gt;next)
+		rc = shpchprm_add_resource(aprh, res-&gt;base, res-&gt;length);
+
+	return rc;
+}
+
+static void acpi_parse_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_io	*dataio;
+	dataio = (struct acpi_resource_io *) data;
+
+	dbg("Io Resource\n");
+	dbg("  %d bit decode\n", ACPI_DECODE_16 == dataio-&gt;io_decode ? 16:10);
+	dbg("  Range minimum base: %08X\n", dataio-&gt;min_base_address);
+	dbg("  Range maximum base: %08X\n", dataio-&gt;max_base_address);
+	dbg("  Alignment: %08X\n", dataio-&gt;alignment);
+	dbg("  Range Length: %08X\n", dataio-&gt;range_length);
+}
+
+static void acpi_parse_fixed_io (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data
+	)
+{
+	struct acpi_resource_fixed_io  *datafio;
+	datafio = (struct acpi_resource_fixed_io *) data;
+
+	dbg("Fixed Io Resource\n");
+	dbg("  Range base address: %08X", datafio-&gt;base_address);
+	dbg("  Range length: %08X", datafio-&gt;range_length);
+}
+
+static void acpi_parse_address16_32 (
+	struct acpi_bridge		*ab,
+	union acpi_resource_data	*data,
+	acpi_resource_type		id
+	)
+{
+	/* 
+	 * acpi_resource_address16 == acpi_resource_address32
+	 * acpi_resource_address16 *data16 = (acpi_resource_address16 *) data;
+	 */
+	struct acpi_resource_address32 *data32 = (struct acpi_resource_address32 *) data;
+	struct pci_resource **aprh, **tprh;
+
+	if (id == ACPI_RSTYPE_ADDRESS16)
+		dbg("acpi_shpchprm:16-Bit Address Space Resource\n");
+	else
+		dbg("acpi_shpchprm:32-Bit Address Space Resource\n");
+
+	switch (data32-&gt;resource_type) {
+	case ACPI_MEMORY_RANGE: 
+		dbg("  Resource Type: Memory Range\n");
+		aprh = &amp;ab-&gt;mem_head;
+		tprh = &amp;ab-&gt;tmem_head;
+
+		switch (data32-&gt;attribute.memory.cache_attribute) {
+		case ACPI_NON_CACHEABLE_MEMORY:
+			dbg("  Type Specific: Noncacheable memory\n");
+			break; 
+		case ACPI_CACHABLE_MEMORY:
+			dbg("  Type Specific: Cacheable memory\n");
+			break; 
+		case ACPI_WRITE_COMBINING_MEMORY:
+			dbg("  Type Specific: Write-combining memory\n");
+			break; 
+		case ACPI_PREFETCHABLE_MEMORY:
+			aprh = &amp;ab-&gt;p_mem_head;
+			dbg("  Type Specific: Prefetchable memory\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid cache attribute\n");
+			break;
+		}
+
+		dbg("  Type Specific: Read%s\n", ACPI_READ_WRITE_MEMORY == data32-&gt;attribute.memory.read_write_attribute ? "/Write":" Only");
+		break;
+
+	case ACPI_IO_RANGE: 
+		dbg("  Resource Type: I/O Range\n");
+		aprh = &amp;ab-&gt;io_head;
+		tprh = &amp;ab-&gt;tio_head;
+
+		switch (data32-&gt;attribute.io.range_attribute) {
+		case ACPI_NON_ISA_ONLY_RANGES:
+			dbg("  Type Specific: Non-ISA Io Addresses\n");
+			break; 
+		case ACPI_ISA_ONLY_RANGES:
+			dbg("  Type Specific: ISA Io Addresses\n");
+			break; 
+		case ACPI_ENTIRE_RANGE:
+			dbg("  Type Specific: ISA and non-ISA Io Addresses\n");
+			break; 
+		default:
+			dbg("  Type Specific: Invalid range attribute\n");
+			break;
+		}
+		break;
+
+	case ACPI_BUS_NUMBER_RANGE: 
+		dbg("  Resource Type: Bus Number Range(fixed)\n");
+		/* fixup to be compatible with the rest of php driver */
+		data32-&gt;min_address_range++;
+		data32-&gt;address_length--;
+		aprh = &amp;ab-&gt;bus_head;
+		tprh = &amp;ab-&gt;tbus_head;
+		break; 
+	default: 
+		dbg("  Resource Type: Invalid resource type. Exiting.\n");
+		return;
+	}
+
+	dbg("  Resource %s\n", ACPI_CONSUMER == data32-&gt;producer_consumer ? "Consumer":"Producer");
+	dbg("  %s decode\n", ACPI_SUB_DECODE == data32-&gt;decode ? "Subtractive":"Positive");
+	dbg("  Min address is %s fixed\n", ACPI_ADDRESS_FIXED == data32-&gt;min_address_fixed ? "":"not");
+	dbg("  Max address is %s fixed\n", ACPI_ADDRESS_FIXED == data32-&gt;max_address_fixed ? "":"not");
+	dbg("  Granularity: %08X\n", data32-&gt;granularity);
+	dbg("  Address range min: %08X\n", data32-&gt;min_address_range);
+	dbg("  Address range max: %08X\n", data32-&gt;max_address_range);
+	dbg("  Address translation offset: %08X\n", data32-&gt;address_translation_offset);
+	dbg("  Address Length: %08X\n", data32-&gt;address_length);
+
+	if (0xFF != data32-&gt;resource_source.index) {
+		dbg("  Resource Source Index: %X\n", data32-&gt;resource_source.index);
+		/* dbg("  Resource Source: %s\n", data32-&gt;resource_source.string_ptr); */
+	}
+
+	shpchprm_add_resource(aprh, data32-&gt;min_address_range, data32-&gt;address_length);
+}
+
+static acpi_status acpi_parse_crs(
+	struct acpi_bridge	*ab,
+	struct acpi_resource	*crsbuf
+	)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_resource	*resource = crsbuf;
+	u8			count = 0;
+	u8			done = 0;
+
+	while (!done) {
+		dbg("acpi_shpchprm: PCI bus 0x%x Resource structure %x.\n", ab-&gt;bus, count++);
+		switch (resource-&gt;id) {
+		case ACPI_RSTYPE_IRQ:
+			dbg("Irq -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_DMA:
+			dbg("DMA -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_START_DPF:
+			dbg("Start DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_DPF:
+			dbg("End DPF -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_IO:
+			acpi_parse_io (ab, &amp;resource-&gt;data);
+			break; 
+		case ACPI_RSTYPE_FIXED_IO:
+			acpi_parse_fixed_io (ab, &amp;resource-&gt;data);
+			break; 
+		case ACPI_RSTYPE_VENDOR:
+			dbg("Vendor -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_END_TAG:
+			dbg("End_tag -------- Resource\n");
+			done = 1;
+			break; 
+		case ACPI_RSTYPE_MEM24:
+			dbg("Mem24 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_MEM32:
+			dbg("Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_FIXED_MEM32:
+			dbg("Fixed Mem32 -------- Resource\n");
+			break; 
+		case ACPI_RSTYPE_ADDRESS16:
+			acpi_parse_address16_32(ab, &amp;resource-&gt;data, ACPI_RSTYPE_ADDRESS16);
+			break; 
+		case ACPI_RSTYPE_ADDRESS32:
+			acpi_parse_address16_32(ab, &amp;resource-&gt;data, ACPI_RSTYPE_ADDRESS32);
+			break; 
+		case ACPI_RSTYPE_ADDRESS64:
+			info("Address64 -------- Resource unparsed\n");
+			break; 
+		case ACPI_RSTYPE_EXT_IRQ:
+			dbg("Ext Irq -------- Resource\n");
+			break; 
+		default:
+			dbg("Invalid -------- resource type 0x%x\n", resource-&gt;id);
+			break;
+		}
+
+		resource = (struct acpi_resource *) ((char *)resource + resource-&gt;length);
+	}
+
+	return status;
+}
+
+static acpi_status acpi_get_crs( struct acpi_bridge	*ab)
+{
+	acpi_status		status;
+	struct acpi_resource	*crsbuf;
+
+	status = acpi_evaluate_crs(ab-&gt;handle, &amp;crsbuf);
+	if (ACPI_SUCCESS(status)) {
+		status = acpi_parse_crs(ab, crsbuf);
+		kfree(crsbuf);
+
+		shpchp_resource_sort_and_combine(&amp;ab-&gt;bus_head);
+		shpchp_resource_sort_and_combine(&amp;ab-&gt;io_head);
+		shpchp_resource_sort_and_combine(&amp;ab-&gt;mem_head);
+		shpchp_resource_sort_and_combine(&amp;ab-&gt;p_mem_head);
+
+		shpchprm_add_resources (&amp;ab-&gt;tbus_head, ab-&gt;bus_head);
+		shpchprm_add_resources (&amp;ab-&gt;tio_head, ab-&gt;io_head);
+		shpchprm_add_resources (&amp;ab-&gt;tmem_head, ab-&gt;mem_head);
+		shpchprm_add_resources (&amp;ab-&gt;tp_mem_head, ab-&gt;p_mem_head);
+	}
+
+	return status;
+}
+
+/* find acpi_bridge downword from ab.  */
+static struct acpi_bridge *
+find_acpi_bridge_by_bus(
+	struct acpi_bridge *ab,
+	int seg,
+	int bus		/* pdev-&gt;subordinate-&gt;number */
+	)
+{
+	struct acpi_bridge	*lab = NULL;
+
+	if (!ab)
+		return NULL;
+
+	if ((ab-&gt;bus == bus) &amp;&amp; (ab-&gt;seg == seg))
+		return ab;
+
+	if (ab-&gt;child)
+		lab = find_acpi_bridge_by_bus(ab-&gt;child, seg, bus);
+
+	if (!lab)
+	if (ab-&gt;next)
+		lab = find_acpi_bridge_by_bus(ab-&gt;next, seg, bus);
+
+	return lab;
+}
+
+/*
+ * Build a device tree of ACPI PCI Bridges
+ */
+static void shpchprm_acpi_register_a_bridge (
+	struct acpi_bridge	**head,
+	struct acpi_bridge	*pab,	/* parent bridge to which child bridge is added */
+	struct acpi_bridge	*cab	/* child bridge to add */
+	)
+{
+	struct acpi_bridge	*lpab;
+	struct acpi_bridge	*lcab;
+
+	lpab = find_acpi_bridge_by_bus(*head, pab-&gt;seg, pab-&gt;bus);
+	if (!lpab) {
+		if (!(pab-&gt;type &amp; BRIDGE_TYPE_HOST))
+			warn("PCI parent bridge s:b(%x:%x) not in list.\n", pab-&gt;seg, pab-&gt;bus);
+		pab-&gt;next = *head;
+		*head = pab;
+		lpab = pab;
+	}
+
+	if ((cab-&gt;type &amp; BRIDGE_TYPE_HOST) &amp;&amp; (pab == cab))
+		return;
+
+	lcab = find_acpi_bridge_by_bus(*head, cab-&gt;seg, cab-&gt;bus);
+	if (lcab) {
+		if ((pab-&gt;bus != lcab-&gt;parent-&gt;bus) || (lcab-&gt;bus != cab-&gt;bus))
+			err("PCI child bridge s:b(%x:%x) in list with diff parent.\n", cab-&gt;seg, cab-&gt;bus);
+		return;
+	} else
+		lcab = cab;
+
+	lcab-&gt;parent = lpab;
+	lcab-&gt;next = lpab-&gt;child;
+	lpab-&gt;child = lcab;
+}
+
+static acpi_status shpchprm_acpi_build_php_slots_callback(
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		bus_num;
+	ulong		seg_num;
+	ulong		sun, adr;
+	ulong		padr = 0;
+	acpi_handle		phandle = NULL;
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*lab;
+	acpi_status		status;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get _SUN */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SUN, NULL, &amp;sun);
+	switch(status) {
+	case AE_NOT_FOUND:
+		return AE_OK;
+	default:
+		if (ACPI_FAILURE(status)) {
+			err("acpi_shpchprm:%s _SUN fail=0x%x\n", path_name, status);
+			return status;
+		}
+	}
+
+	/* get _ADR. _ADR must exist if _SUN exists */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &amp;adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return status;
+	}
+
+	dbg("acpi_shpchprm:%s sun=0x%08x adr=0x%08x\n", path_name, (u32)sun, (u32)adr);
+
+	status = acpi_get_parent(handle, &amp;phandle);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s get_parent fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	bus_num = pab-&gt;bus;
+	seg_num = pab-&gt;seg;
+
+	if (pab-&gt;bus == bus_num) {
+		lab = pab;
+	} else {
+		dbg("WARN: pab is not parent\n");
+		lab = find_acpi_bridge_by_bus(pab, seg_num, bus_num);
+		if (!lab) {
+			dbg("acpi_shpchprm: alloc new P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+			lab = (struct acpi_bridge *)kmalloc(sizeof(struct acpi_bridge), GFP_KERNEL);
+			if (!lab) {
+				err("acpi_shpchprm: alloc for ab fail\n");
+				return AE_NO_MEMORY;
+			}
+			memset(lab, 0, sizeof(struct acpi_bridge));
+
+			lab-&gt;handle = phandle;
+			lab-&gt;pbus = pab-&gt;bus;
+			lab-&gt;pdevice = (int)(padr &gt;&gt; 16) &amp; 0xffff;
+			lab-&gt;pfunction = (int)(padr &amp; 0xffff);
+			lab-&gt;bus = (int)bus_num;
+			lab-&gt;scanned = 0;
+			lab-&gt;type = BRIDGE_TYPE_P2P;
+
+			shpchprm_acpi_register_a_bridge (&amp;acpi_bridges_head, pab, lab);
+		} else
+			dbg("acpi_shpchprm: found P2P bridge(%x) for sun(%08x)\n", (u32)bus_num, (u32)sun);
+	}
+
+	acpi_add_slot_to_php_slots(lab, (int)bus_num, handle, (u32)adr, (u32)sun);
+	return (status);
+}
+
+static int shpchprm_acpi_build_php_slots(
+	struct acpi_bridge	*ab,
+	u32			depth
+	)
+{
+	acpi_status	status;
+	u8		*path_name = acpi_path_name(ab-&gt;handle);
+
+	/* Walk down this pci bridge to get _SUNs if any behind P2P */
+	status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+				ab-&gt;handle,
+				depth,
+				shpchprm_acpi_build_php_slots_callback,
+				ab,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		dbg("acpi_shpchprm:%s walk for _SUN on pci bridge seg:bus(%x:%x) fail=0x%x\n", path_name, ab-&gt;seg, ab-&gt;bus, status);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void build_a_bridge(
+	struct acpi_bridge	*pab,
+	struct acpi_bridge	*ab
+	)
+{
+	u8		*path_name = acpi_path_name(ab-&gt;handle);
+
+	shpchprm_acpi_register_a_bridge (&amp;acpi_bridges_head, pab, ab);
+
+	switch (ab-&gt;type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("acpi_shpchprm: Registered PCI HOST Bridge(%02x)    on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab-&gt;bus, ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction, path_name);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("acpi_shpchprm: Registered PCI  P2P Bridge(%02x-%02x) on s:b:d:f(%02x:%02x:%02x:%02x) [%s]\n",
+			ab-&gt;pbus, ab-&gt;bus, ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction, path_name);
+		break;
+	};
+
+	/* build any immediate PHP slots under this pci bridge */
+	shpchprm_acpi_build_php_slots(ab, 1);
+}
+
+static struct acpi_bridge * add_p2p_bridge(
+	acpi_handle handle,
+	struct acpi_bridge	*pab,	/* parent */
+	ulong	adr
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_dev	*pdev;
+	ulong		devnum, funcnum;
+	u8			*path_name = acpi_path_name(handle);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_shpchprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	devnum = (adr &gt;&gt; 16) &amp; 0xffff;
+	funcnum = adr &amp; 0xffff;
+
+	pdev = pci_find_slot(pab-&gt;bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev || !pdev-&gt;subordinate) {
+		err("acpi_shpchprm:%s is not a P2P Bridge\n", path_name);
+		kfree(ab);
+		return NULL;
+	}
+
+	ab-&gt;handle = handle;
+	ab-&gt;seg = pab-&gt;seg;
+	ab-&gt;pbus = pab-&gt;bus;		/* or pdev-&gt;bus-&gt;number */
+	ab-&gt;pdevice = devnum;		/* or PCI_SLOT(pdev-&gt;devfn) */
+	ab-&gt;pfunction = funcnum;	/* or PCI_FUNC(pdev-&gt;devfn) */
+	ab-&gt;bus = pdev-&gt;subordinate-&gt;number;
+	ab-&gt;scanned = 0;
+	ab-&gt;type = BRIDGE_TYPE_P2P;
+
+	dbg("acpi_shpchprm: P2P(%x-%x) on pci=b:d:f(%x:%x:%x) acpi=b:d:f(%x:%x:%x) [%s]\n",
+		pab-&gt;bus, ab-&gt;bus, pdev-&gt;bus-&gt;number, PCI_SLOT(pdev-&gt;devfn), PCI_FUNC(pdev-&gt;devfn),
+		pab-&gt;bus, (u32)devnum, (u32)funcnum, path_name);
+
+	build_a_bridge(pab, ab);
+
+	return ab;
+}
+
+static acpi_status scan_p2p_bridge(
+	acpi_handle		handle,
+	u32			Level,
+	void			*context,
+	void			**retval
+	)
+{
+	struct acpi_bridge	*pab = (struct acpi_bridge *)context;
+	struct acpi_bridge	*ab;
+	acpi_status		status;
+	ulong		adr = 0;
+	u8			*path_name = acpi_path_name(handle);
+	ulong		devnum, funcnum;
+	struct pci_dev	*pdev;
+
+	/* get device, function */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &amp;adr);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND)
+			err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return AE_OK;
+	}
+
+	devnum = (adr &gt;&gt; 16) &amp; 0xffff;
+	funcnum = adr &amp; 0xffff;
+
+	pdev = pci_find_slot(pab-&gt;bus, PCI_DEVFN(devnum, funcnum));
+	if (!pdev)
+		return AE_OK;
+	if (!pdev-&gt;subordinate)
+		return AE_OK;
+
+	ab = add_p2p_bridge(handle, pab, adr);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					(u32)1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static struct acpi_bridge * add_host_bridge(
+	acpi_handle handle,
+	ulong	segnum,
+	ulong	busnum
+	)
+{
+	ulong			adr = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get device, function: host br adr is always 0000 though.  */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &amp;adr);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s _ADR fail=0x%x\n", path_name, status);
+		return NULL;
+	}
+	dbg("acpi_shpchprm: ROOT PCI seg(0x%x)bus(0x%x)dev(0x%x)func(0x%x) [%s]\n", (u32)segnum, (u32)busnum, 
+		(u32)(adr &gt;&gt; 16) &amp; 0xffff, (u32)adr &amp; 0xffff, path_name);
+
+	ab = (struct acpi_bridge *) kmalloc (sizeof(struct acpi_bridge), GFP_KERNEL);
+	if (!ab) {
+		err("acpi_shpchprm: alloc for ab fail\n");
+		return NULL;
+	}
+	memset(ab, 0, sizeof(struct acpi_bridge));
+
+	ab-&gt;handle = handle;
+	ab-&gt;seg = (int)segnum;
+	ab-&gt;bus = ab-&gt;pbus = (int)busnum;
+	ab-&gt;pdevice = (int)(adr &gt;&gt; 16) &amp; 0xffff;
+	ab-&gt;pfunction = (int)(adr &amp; 0xffff);
+	ab-&gt;scanned = 0;
+	ab-&gt;type = BRIDGE_TYPE_HOST;
+
+	/* get root pci bridge's current resources */
+	status = acpi_get_crs(ab);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s evaluate _CRS fail=0x%x\n", path_name, status);
+		kfree(ab);
+		return NULL;
+	}
+	build_a_bridge(ab, ab);
+
+	return ab;
+}
+
+static acpi_status acpi_scan_from_root_pci_callback (
+	acpi_handle	handle,
+	u32			Level,
+	void		*context,
+	void		**retval
+	)
+{
+	ulong		segnum = 0;
+	ulong		busnum = 0;
+	acpi_status		status;
+	struct acpi_bridge	*ab;
+	u8			*path_name = acpi_path_name(handle);
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &amp;segnum);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			err("acpi_shpchprm:%s evaluate _SEG fail=0x%x\n", path_name, status);
+			return status;
+		}
+		segnum = 0;
+	}
+
+	/* get bus number of this pci root bridge */
+	status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, &amp;busnum);
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:%s evaluate _BBN fail=0x%x\n", path_name, status);
+		return (status);
+	}
+
+	ab = add_host_bridge(handle, segnum, busnum);
+	if (ab) {
+		status = acpi_walk_namespace ( ACPI_TYPE_DEVICE,
+					handle,
+					1,
+					scan_p2p_bridge,
+					ab,
+					NULL);
+		if (ACPI_FAILURE(status))
+			dbg("acpi_shpchprm:%s find_p2p fail=0x%x\n", path_name, status);
+	}
+
+	return AE_OK;
+}
+
+static int shpchprm_acpi_scan_pci (void)
+{
+	acpi_status	status;
+
+	/*
+	 * TBD: traverse LDM device tree with the help of
+	 *  unified ACPI augmented for php device population.
+	 */
+	status = acpi_get_devices ( PCI_ROOT_HID_STRING,
+				acpi_scan_from_root_pci_callback,
+				NULL,
+				NULL );
+	if (ACPI_FAILURE(status)) {
+		err("acpi_shpchprm:get_device PCI ROOT HID fail=0x%x\n", status);
+		return -1;
+	}
+
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctlr_type)
+{
+	int	rc;
+
+	if (ctlr_type != PCI)
+		return -ENODEV;
+
+	dbg("shpchprm ACPI init &lt;enter&gt;\n");
+	acpi_bridges_head = NULL;
+
+	/* construct PCI bus:device tree of acpi_handles */
+	rc = shpchprm_acpi_scan_pci();
+	if (rc)
+		return rc;
+
+	dbg("shpchprm ACPI init %s\n", (rc)?"fail":"success");
+	return rc;
+}
+
+static void free_a_slot(struct acpi_php_slot *aps)
+{
+	dbg("        free a php func of slot(0x%02x) on PCI b:d:f=0x%02x:%02x:%02x\n", aps-&gt;sun, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+
+	free_pci_resource (aps-&gt;io_head);
+	free_pci_resource (aps-&gt;bus_head);
+	free_pci_resource (aps-&gt;mem_head);
+	free_pci_resource (aps-&gt;p_mem_head);
+
+	kfree(aps);
+}
+
+static void free_a_bridge( struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps, *next;
+
+	switch (ab-&gt;type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("Free ACPI PCI HOST Bridge(%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab-&gt;bus, acpi_path_name(ab-&gt;handle), ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction);
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("Free ACPI PCI P2P Bridge(%x-%x) [%s] on s:b:d:f(%x:%x:%x:%x)\n",
+			ab-&gt;pbus, ab-&gt;bus, acpi_path_name(ab-&gt;handle), ab-&gt;seg, ab-&gt;pbus, ab-&gt;pdevice, ab-&gt;pfunction);
+		break;
+	};
+
+	/* free slots first */
+	for (aps = ab-&gt;slots; aps; aps = next) {
+		next = aps-&gt;next;
+		free_a_slot(aps);
+	}
+
+	free_pci_resource (ab-&gt;io_head);
+	free_pci_resource (ab-&gt;tio_head);
+	free_pci_resource (ab-&gt;bus_head);
+	free_pci_resource (ab-&gt;tbus_head);
+	free_pci_resource (ab-&gt;mem_head);
+	free_pci_resource (ab-&gt;tmem_head);
+	free_pci_resource (ab-&gt;p_mem_head);
+	free_pci_resource (ab-&gt;tp_mem_head);
+
+	kfree(ab);
+}
+
+static void shpchprm_free_bridges ( struct acpi_bridge	*ab)
+{
+	if (ab-&gt;child)
+		shpchprm_free_bridges (ab-&gt;child);
+
+	if (ab-&gt;next)
+		shpchprm_free_bridges (ab-&gt;next);
+
+	free_a_bridge(ab);
+}
+
+void shpchprm_cleanup(void)
+{
+	shpchprm_free_bridges (acpi_bridges_head);
+}
+
+static int get_number_of_slots (
+	struct acpi_bridge	*ab,
+	int				selfonly
+	)
+{
+	struct acpi_php_slot	*aps;
+	int	prev_slot = -1;
+	int	slot_num = 0;
+
+	for ( aps = ab-&gt;slots; aps; aps = aps-&gt;next)
+		if (aps-&gt;dev != prev_slot) {
+			prev_slot = aps-&gt;dev;
+			slot_num++;
+		}
+
+	if (ab-&gt;child)
+		slot_num += get_number_of_slots (ab-&gt;child, 0);
+
+	if (selfonly)
+		return slot_num;
+
+	if (ab-&gt;next)
+		slot_num += get_number_of_slots (ab-&gt;next, 0);
+
+	return slot_num;
+}
+
+static int print_acpi_resources (struct acpi_bridge	*ab)
+{
+	struct acpi_php_slot	*aps;
+	int	i;
+
+	switch (ab-&gt;type) {
+	case BRIDGE_TYPE_HOST:
+		dbg("PCI HOST Bridge (%x) [%s]\n", ab-&gt;bus, acpi_path_name(ab-&gt;handle));
+		break;
+	case BRIDGE_TYPE_P2P:
+		dbg("PCI P2P Bridge (%x-%x) [%s]\n", ab-&gt;pbus, ab-&gt;bus, acpi_path_name(ab-&gt;handle));
+		break;
+	};
+
+	print_pci_resources (ab);
+
+	for ( i = -1, aps = ab-&gt;slots; aps; aps = aps-&gt;next) {
+		if (aps-&gt;dev == i)
+			continue;
+		dbg("  Slot sun(%x) s:b:d:f(%02x:%02x:%02x:%02x)\n", aps-&gt;sun, aps-&gt;seg, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+		print_slot_resources(aps);
+		i = aps-&gt;dev;
+	}
+
+	if (ab-&gt;child)
+		print_acpi_resources (ab-&gt;child);
+
+	if (ab-&gt;next)
+		print_acpi_resources (ab-&gt;next);
+
+	return 0;
+}
+
+int shpchprm_print_pirt(void)
+{
+	dbg("SHPCHPRM ACPI Slots\n");
+	print_acpi_resources (acpi_bridges_head);
+	return 0;
+}
+
+static struct acpi_php_slot * get_acpi_slot (
+	struct acpi_bridge *ab,
+	u32 sun
+	)
+{
+	struct acpi_php_slot	*aps = NULL;
+
+	for ( aps = ab-&gt;slots; aps; aps = aps-&gt;next)
+		if (aps-&gt;sun == sun)
+			return aps;
+
+	if (!aps &amp;&amp; ab-&gt;child) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab-&gt;child, sun);
+		if (aps)
+			return aps;
+	}
+
+	if (!aps &amp;&amp; ab-&gt;next) {
+		aps = (struct acpi_php_slot *)get_acpi_slot (ab-&gt;next, sun);
+		if (aps)
+			return aps;
+	}
+
+	return aps;
+
+}
+
+void * shpchprm_get_slot(struct slot *slot)
+{
+	struct acpi_bridge	*ab = acpi_bridges_head;
+	struct acpi_php_slot	*aps = get_acpi_slot (ab, slot-&gt;number);
+
+	aps-&gt;slot = slot;
+
+	dbg("Got acpi slot sun(%x): s:b:d:f(%x:%x:%x:%x)\n", aps-&gt;sun, aps-&gt;seg, aps-&gt;bus, aps-&gt;dev, aps-&gt;fun);
+
+	return (void *)aps;
+}
+
+static void shpchprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func-&gt;bus_head);
+	}
+	if (func-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func-&gt;io_head);
+	}
+	if (func-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func-&gt;mem_head);
+	}
+	if (func-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func-&gt;p_mem_head);
+	}
+}
+
+static void shpchprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl-&gt;bus_head);
+	}
+	if (ctrl-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl-&gt;io_head);
+	}
+	if (ctrl-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl-&gt;mem_head);
+	}
+	if (ctrl-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl-&gt;p_mem_head);
+	}
+}
+
+static int shpchprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = shpchprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = shpchprm_delete_resources (&amp;ctrl-&gt;bus_head, func-&gt;bus_head);
+		rc |= shpchprm_delete_resources (&amp;ctrl-&gt;io_head, func-&gt;io_head);
+		rc |= shpchprm_delete_resources (&amp;ctrl-&gt;mem_head, func-&gt;mem_head);
+		rc |= shpchprm_delete_resources (&amp;ctrl-&gt;p_mem_head, func-&gt;p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl-&gt;bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn &lt; 32; devn++) {
+		for (funn = 0; funn &lt; 8; funn++) {
+			if (devn == ctrl-&gt;device &amp;&amp; funn == ctrl-&gt;function)
+				continue;
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+			pci_bus_read_config_dword(ctrl-&gt;pci_bus, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &amp;vid);
+
+			if (vid != 0xFFFFFFFF) {
+				func = shpchp_slot_find(busn, devn, funn);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl-&gt;bus);
+				shpchprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int bind_pci_resources(
+	struct controller 	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	status = 0;
+
+	if (ab-&gt;bus_head) {
+		dbg("bapr:  BUS Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = shpchprm_add_resources (&amp;ctrl-&gt;bus_head, ab-&gt;bus_head);
+		if (shpchprm_delete_resources (&amp;ab-&gt;bus_head, ctrl-&gt;bus_head))
+			warn("bapr:  cannot sub BUS Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  BUS Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No BUS Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	if (ab-&gt;io_head) {
+		dbg("bapr:  IO Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = shpchprm_add_resources (&amp;ctrl-&gt;io_head, ab-&gt;io_head);
+		if (shpchprm_delete_resources (&amp;ab-&gt;io_head, ctrl-&gt;io_head))
+			warn("bapr:  cannot sub IO Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  IO Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No  IO Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	if (ab-&gt;mem_head) {
+		dbg("bapr:  MEM Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = shpchprm_add_resources (&amp;ctrl-&gt;mem_head, ab-&gt;mem_head);
+		if (shpchprm_delete_resources (&amp;ab-&gt;mem_head, ctrl-&gt;mem_head))
+			warn("bapr:  cannot sub MEM Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  MEM Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No MEM Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	if (ab-&gt;p_mem_head) {
+		dbg("bapr:  PMEM Resources add on PCI 0x%x\n", ab-&gt;bus);
+		status = shpchprm_add_resources (&amp;ctrl-&gt;p_mem_head, ab-&gt;p_mem_head);
+		if (shpchprm_delete_resources (&amp;ab-&gt;p_mem_head, ctrl-&gt;p_mem_head))
+			warn("bapr:  cannot sub PMEM Resource on PCI 0x%x\n", ab-&gt;bus);
+		if (status) {
+			err("bapr:  PMEM Resource add on PCI 0x%x: fail=0x%x\n", ab-&gt;bus, status);
+			return status;
+		}
+	} else
+		info("bapr:  No PMEM Resource on PCI 0x%x.\n", ab-&gt;bus);
+
+	return status;
+}
+
+static int no_pci_resources( struct acpi_bridge *ab)
+{
+	return !(ab-&gt;p_mem_head || ab-&gt;mem_head || ab-&gt;io_head || ab-&gt;bus_head);
+}
+
+static int find_pci_bridge_resources (
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+	struct pci_func func;
+
+	memset(&amp;func, 0, sizeof(struct pci_func));
+
+	func.bus = ab-&gt;pbus;
+	func.device = ab-&gt;pdevice;
+	func.function = ab-&gt;pfunction;
+	func.is_a_board = 1;
+
+	/* Get used resources for this PCI bridge */
+	rc = shpchp_save_used_resources (ctrl, &amp;func, !DISABLE_CARD);
+
+	ab-&gt;io_head = func.io_head;
+	ab-&gt;mem_head = func.mem_head;
+	ab-&gt;p_mem_head = func.p_mem_head;
+	ab-&gt;bus_head = func.bus_head;
+	if (ab-&gt;bus_head)
+		shpchprm_delete_resource(&amp;ab-&gt;bus_head, ctrl-&gt;bus, 1);
+
+	return rc;
+}
+
+static int get_pci_resources_from_bridge(
+	struct controller *ctrl,
+	struct acpi_bridge *ab
+	)
+{
+	int	rc = 0;
+
+	dbg("grfb:  Get Resources for PCI 0x%x from actual PCI bridge 0x%x.\n", ctrl-&gt;bus, ab-&gt;bus);
+
+	rc = find_pci_bridge_resources (ctrl, ab);
+
+	shpchp_resource_sort_and_combine(&amp;ab-&gt;bus_head);
+	shpchp_resource_sort_and_combine(&amp;ab-&gt;io_head);
+	shpchp_resource_sort_and_combine(&amp;ab-&gt;mem_head);
+	shpchp_resource_sort_and_combine(&amp;ab-&gt;p_mem_head);
+
+	shpchprm_add_resources (&amp;ab-&gt;tbus_head, ab-&gt;bus_head);
+	shpchprm_add_resources (&amp;ab-&gt;tio_head, ab-&gt;io_head);
+	shpchprm_add_resources (&amp;ab-&gt;tmem_head, ab-&gt;mem_head);
+	shpchprm_add_resources (&amp;ab-&gt;tp_mem_head, ab-&gt;p_mem_head);
+
+	return rc;
+}
+
+static int get_pci_resources(
+	struct controller	*ctrl,
+	struct acpi_bridge	*ab
+	)
+{
+	int	rc = 0;
+
+	if (no_pci_resources(ab)) {
+		dbg("spbr:PCI 0x%x has no resources. Get parent resources.\n", ab-&gt;bus);
+		rc = get_pci_resources_from_bridge(ctrl, ab);
+	}
+
+	return rc;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int offset = devnum - ctrl-&gt;slot_device_offset;
+
+	dbg("%s: ctrl-&gt;slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl-&gt;slot_num_inc, offset);
+	*sun = (u8) (ctrl-&gt;first_slot + ctrl-&gt;slot_num_inc *offset);
+	return 0;
+}
+
+/*
+ * Get resources for this ctrl.
+ *  1. get total resources from ACPI _CRS or bridge (this ctrl)
+ *  2. find used resources of existing adapters
+ *	3. subtract used resources from total resources
+ */
+int shpchprm_find_available_resources( struct controller *ctrl)
+{
+	int rc = 0;
+	struct acpi_bridge	*ab;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl-&gt;seg, ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+	if (!ab) {
+		err("pfar:cannot locate acpi bridge of PCI 0x%x.\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+		return -1;
+	}
+	if (no_pci_resources(ab)) {
+		rc = get_pci_resources(ctrl, ab);
+		if (rc) {
+			err("pfar:cannot get pci resources of PCI 0x%x.\n",ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+			return -1;
+		}
+	}
+
+	rc = bind_pci_resources(ctrl, ab);
+	dbg("pfar:pre-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+	shpchprm_dump_ctrl_res(ctrl);
+
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("pfar:post-Bind PCI 0x%x Ctrl Resource Dump\n", ctrl-&gt;pci_dev-&gt;subordinate-&gt;number);
+	shpchprm_dump_ctrl_res(ctrl);
+
+	return rc;
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type
+	)
+{
+	struct acpi_bridge	*ab;
+	struct pci_bus lpci_bus, *pci_bus;
+	int				rc = 0;
+	unsigned int	devfn;
+	u8				cls= 0x08;	/* default cache line size	*/
+	u8				lt = 0x40;	/* default latency timer	*/
+	u8				ep = 0;
+	u8				es = 0;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl-&gt;seg, ctrl-&gt;bus);
+
+	if (ab) {
+		if (ab-&gt;_hpp) {
+			lt  = (u8)ab-&gt;_hpp-&gt;latency_timer;
+			cls = (u8)ab-&gt;_hpp-&gt;cache_line_size;
+			ep  = (u8)ab-&gt;_hpp-&gt;enable_perr;
+			es  = (u8)ab-&gt;_hpp-&gt;enable_serr;
+		} else
+			dbg("_hpp: no _hpp for B/D/F=%#x/%#x/%#x. use default value\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+	} else
+		dbg("_hpp: no acpi bridge for B/D/F = %#x/%#x/%#x. use default value\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, lt);
+	}
+
+	/* set base Latency Timer */
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, lt);
+	dbg("  set latency timer  =0x%02x: %x\n", lt, rc);
+
+	rc |= pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, cls);
+	dbg("  set cache_line_size=0x%02x: %x\n", cls, rc);
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, cmd, bcommand, bcmd;
+	struct pci_bus lpci_bus, *pci_bus;
+	struct acpi_bridge	*ab;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &amp;command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;bcommand);
+	}
+
+	cmd = command  = command | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	bcmd = bcommand  = bcommand | PCI_BRIDGE_CTL_NO_ISA;
+
+	ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl-&gt;seg, ctrl-&gt;bus);
+	if (ab) {
+		if (ab-&gt;_hpp) {
+			if (ab-&gt;_hpp-&gt;enable_perr) {
+				command |= PCI_COMMAND_PARITY;
+				bcommand |= PCI_BRIDGE_CTL_PARITY;
+			} else {
+				command &amp;= ~PCI_COMMAND_PARITY;
+				bcommand &amp;= ~PCI_BRIDGE_CTL_PARITY;
+			}
+			if (ab-&gt;_hpp-&gt;enable_serr) {
+				command |= PCI_COMMAND_SERR;
+				bcommand |= PCI_BRIDGE_CTL_SERR;
+			} else {
+				command &amp;= ~PCI_COMMAND_SERR;
+				bcommand &amp;= ~PCI_BRIDGE_CTL_SERR;
+			}
+		} else
+			dbg("no _hpp for B/D/F = %#x/%#x/%#x.\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+	} else
+		dbg("no acpi bridge for B/D/F = %#x/%#x/%#x.\n", func-&gt;bus, func-&gt;device, func-&gt;function);
+
+	if (command != cmd) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+	}
+	if ((card_type == PCI_HEADER_TYPE_BRIDGE) &amp;&amp; (bcommand != bcmd)) {
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
diff -puN /dev/null drivers/pci/hotplug/shpchprm.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchprm.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,56 @@
+/*
+ * SHPCHPRM : SHPCHP Resource Manager for ACPI/non-ACPI platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#ifndef _SHPCHPRM_H_
+#define _SHPCHPRM_H_
+
+#ifdef	CONFIG_HOTPLUG_PCI_SHPC_PHPRM_LEGACY
+#include "shpchprm_legacy.h"
+#else
+#include "shpchprm_nonacpi.h"
+#endif
+
+int shpchprm_init(enum php_ctlr_type ct);
+void shpchprm_cleanup(void);
+int shpchprm_print_pirt(void);
+void *shpchprm_get_slot(struct slot *slot);
+int shpchprm_find_available_resources(struct controller *ctrl);
+int shpchprm_set_hpp(struct controller *ctrl, struct pci_func *func, u8 card_type);
+void shpchprm_enable_card(struct controller *ctrl, struct pci_func *func, u8 card_type);
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum);
+
+#ifdef	DEBUG
+#define RES_CHECK(this, bits)	\
+	{ if (((this) &amp; (bits - 1))) \
+		printk("%s:%d ERR: potential res loss!\n", __FUNCTION__, __LINE__); }
+#else
+#define RES_CHECK(this, bits)
+#endif
+
+#endif				/* _SHPCHPRM_H_ */
diff -puN /dev/null drivers/pci/hotplug/shpchprm_legacy.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchprm_legacy.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,474 @@
+/*
+ * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;,&lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#ifdef CONFIG_IA64
+#include &lt;asm/iosapic.h&gt;
+#endif
+#include "shpchp.h"
+#include "shpchprm.h"
+#include "shpchprm_legacy.h"
+
+static void *shpchp_rom_start;
+static u16 unused_IRQ;
+
+void shpchprm_cleanup()
+{
+	if (shpchp_rom_start)
+		iounmap(shpchp_rom_start);
+}
+
+int shpchprm_print_pirt()
+{
+	return 0;
+}
+
+void * shpchprm_get_slot(struct slot *slot)
+{
+	return NULL;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int	offset = devnum - ctrl-&gt;slot_device_offset;
+
+	*sun = (u8) (ctrl-&gt;first_slot + ctrl-&gt;slot_num_inc * offset);
+	return 0;
+}
+
+/* Find the Hot Plug Resource Table in the specified region of memory */
+static void *detect_HRT_floating_pointer(void *begin, void *end)
+{
+	void *fp;
+	void *endp;
+	u8 temp1, temp2, temp3, temp4;
+	int status = 0;
+
+	endp = (end - sizeof(struct hrt) + 1);
+
+	for (fp = begin; fp &lt;= endp; fp += 16) {
+		temp1 = readb(fp + SIG0);
+		temp2 = readb(fp + SIG1);
+		temp3 = readb(fp + SIG2);
+		temp4 = readb(fp + SIG3);
+		if (temp1 == '$' &amp;&amp; temp2 == 'H' &amp;&amp; temp3 == 'R' &amp;&amp; temp4 == 'T') {
+			status = 1;
+			break;
+		}
+	}
+
+	if (!status)
+		fp = NULL;
+
+	dbg("Discovered Hotplug Resource Table at %p\n", fp);
+	return fp;
+}
+
+#if link_available
+/*
+ *  Links available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *
+ *  Returns 0 if success
+ */
+static int
+link_available_resources (
+	struct controller *ctrl,
+	struct pci_func *func,
+	int index )
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+#endif
+
+/*
+ * shpchprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int shpchprm_find_available_resources(struct controller *ctrl)
+{
+	u8 populated_slot;
+	u8 bridged_slot;
+	void *one_slot;
+	struct pci_func *func = NULL;
+	int i = 10, index = 0;
+	u32 temp_dword, rc;
+	ulong temp_ulong;
+	struct pci_resource *mem_node;
+	struct pci_resource *p_mem_node;
+	struct pci_resource *io_node;
+	struct pci_resource *bus_node;
+	void *rom_resource_table;
+	struct pci_bus lpci_bus, *pci_bus;
+	u8 cfgspc_irq, temp;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	rom_resource_table = detect_HRT_floating_pointer(shpchp_rom_start, shpchp_rom_start + 0xffff);
+	dbg("rom_resource_table = %p\n", rom_resource_table);
+	if (rom_resource_table == NULL)
+		return -ENODEV;
+
+	/* Sum all resources and setup resource maps */
+	unused_IRQ = readl(rom_resource_table + UNUSED_IRQ);
+	dbg("unused_IRQ = %x\n", unused_IRQ);
+
+	temp = 0;
+	while (unused_IRQ) {
+		if (unused_IRQ &amp; 1) {
+			shpchp_disk_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ &gt;&gt; 1;
+		temp++;
+	}
+
+	dbg("shpchp_disk_irq= %d\n", shpchp_disk_irq);
+	unused_IRQ = unused_IRQ &gt;&gt; 1;
+	temp++;
+
+	while (unused_IRQ) {
+		if (unused_IRQ &amp; 1) {
+			shpchp_nic_irq = temp;
+			break;
+		}
+		unused_IRQ = unused_IRQ &gt;&gt; 1;
+		temp++;
+	}
+
+	dbg("shpchp_nic_irq= %d\n", shpchp_nic_irq);
+	unused_IRQ = readl(rom_resource_table + PCIIRQ);
+
+	temp = 0;
+
+	pci_read_config_byte(ctrl-&gt;pci_dev, PCI_INTERRUPT_LINE, &amp;cfgspc_irq);
+
+	if (!shpchp_nic_irq) {
+		shpchp_nic_irq = cfgspc_irq;
+	}
+
+	if (!shpchp_disk_irq) {
+		shpchp_disk_irq = cfgspc_irq;
+	}
+
+	dbg("shpchp_disk_irq, shpchp_nic_irq= %d, %d\n", shpchp_disk_irq, shpchp_nic_irq);
+
+	one_slot = rom_resource_table + sizeof(struct hrt);
+
+	i = readb(rom_resource_table + NUMBER_OF_ENTRIES);
+	dbg("number_of_entries = %d\n", i);
+
+	if (!readb(one_slot + SECONDARY_BUS))
+		return (1);
+
+	dbg("dev|IO base|length|MEMbase|length|PM base|length|PB SB MB\n");
+
+	while (i &amp;&amp; readb(one_slot + SECONDARY_BUS)) {
+		u8 dev_func = readb(one_slot + DEV_FUNC);
+		u8 primary_bus = readb(one_slot + PRIMARY_BUS);
+		u8 secondary_bus = readb(one_slot + SECONDARY_BUS);
+		u8 max_bus = readb(one_slot + MAX_BUS);
+		u16 io_base = readw(one_slot + IO_BASE);
+		u16 io_length = readw(one_slot + IO_LENGTH);
+		u16 mem_base = readw(one_slot + MEM_BASE);
+		u16 mem_length = readw(one_slot + MEM_LENGTH);
+		u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE);
+		u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH);
+
+		dbg("%2.2x |  %4.4x | %4.4x |  %4.4x | %4.4x |  %4.4x | %4.4x |%2.2x %2.2x %2.2x\n",
+				dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length,
+				primary_bus, secondary_bus, max_bus);
+
+		/* If this entry isn't for our controller's bus, ignore it */
+		if (primary_bus != ctrl-&gt;slot_bus) {
+			i--;
+			one_slot += sizeof(struct slot_rt);
+			continue;
+		}
+		/* find out if this entry is for an occupied slot */
+		temp_dword = 0xFFFFFFFF;
+		pci_bus-&gt;number = primary_bus;
+		pci_bus_read_config_dword(pci_bus, dev_func, PCI_VENDOR_ID, &amp;temp_dword);
+
+		dbg("temp_D_word = %x\n", temp_dword);
+
+		if (temp_dword != 0xFFFFFFFF) {
+			index = 0;
+			func = shpchp_slot_find(primary_bus, dev_func &gt;&gt; 3, 0);
+
+			while (func &amp;&amp; (func-&gt;function != (dev_func &amp; 0x07))) {
+				dbg("func = %p b:d:f(%x:%x:%x)\n", func, primary_bus, dev_func &gt;&gt; 3, index);
+				func = shpchp_slot_find(primary_bus, dev_func &gt;&gt; 3, index++);
+			}
+
+			/* If we can't find a match, skip this table entry */
+			if (!func) {
+				i--;
+				one_slot += sizeof(struct slot_rt);
+				continue;
+			}
+			/* this may not work and shouldn't be used */
+			if (secondary_bus != primary_bus)
+				bridged_slot = 1;
+			else
+				bridged_slot = 0;
+
+			populated_slot = 1;
+		} else {
+			populated_slot = 0;
+			bridged_slot = 0;
+		}
+		dbg("slot populated =%s \n", populated_slot?"yes":"no");
+
+		/* If we've got a valid IO base, use it */
+
+		temp_ulong = io_base + io_length;
+
+		if ((io_base) &amp;&amp; (temp_ulong &lt;= 0x10000)) {
+			io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!io_node)
+				return -ENOMEM;
+
+			io_node-&gt;base = (ulong)io_base;
+			io_node-&gt;length = (ulong)io_length;
+			dbg("found io_node(base, length) = %x, %x\n", io_node-&gt;base, io_node-&gt;length);
+
+			if (!populated_slot) {
+				io_node-&gt;next = ctrl-&gt;io_head;
+				ctrl-&gt;io_head = io_node;
+			} else {
+				io_node-&gt;next = func-&gt;io_head;
+				func-&gt;io_head = io_node;
+			}
+		}
+
+		/* If we've got a valid memory base, use it */
+		temp_ulong = mem_base + mem_length;
+		if ((mem_base) &amp;&amp; (temp_ulong &lt;= 0x10000)) {
+			mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!mem_node)
+				return -ENOMEM;
+
+			mem_node-&gt;base = (ulong)mem_base &lt;&lt; 16;
+			mem_node-&gt;length = (ulong)(mem_length &lt;&lt; 16);
+			dbg("found mem_node(base, length) = %x, %x\n", mem_node-&gt;base, mem_node-&gt;length);
+
+			if (!populated_slot) {
+				mem_node-&gt;next = ctrl-&gt;mem_head;
+				ctrl-&gt;mem_head = mem_node;
+			} else {
+				mem_node-&gt;next = func-&gt;mem_head;
+				func-&gt;mem_head = mem_node;
+			}
+		}
+
+		/*
+		 * If we've got a valid prefetchable memory base, and
+		 * the base + length isn't greater than 0xFFFF
+		 */
+		temp_ulong = pre_mem_base + pre_mem_length;
+		if ((pre_mem_base) &amp;&amp; (temp_ulong &lt;= 0x10000)) {
+			p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!p_mem_node)
+				return -ENOMEM;
+
+			p_mem_node-&gt;base = (ulong)pre_mem_base &lt;&lt; 16;
+			p_mem_node-&gt;length = (ulong)pre_mem_length &lt;&lt; 16;
+			dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node-&gt;base, p_mem_node-&gt;length);
+
+			if (!populated_slot) {
+				p_mem_node-&gt;next = ctrl-&gt;p_mem_head;
+				ctrl-&gt;p_mem_head = p_mem_node;
+			} else {
+				p_mem_node-&gt;next = func-&gt;p_mem_head;
+				func-&gt;p_mem_head = p_mem_node;
+			}
+		}
+
+		/*
+		 * If we've got a valid bus number, use it
+		 * The second condition is to ignore bus numbers on
+		 * populated slots that don't have PCI-PCI bridges
+		 */
+		if (secondary_bus &amp;&amp; (secondary_bus != primary_bus)) {
+			bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!bus_node)
+				return -ENOMEM;
+
+			bus_node-&gt;base = (ulong)secondary_bus;
+			bus_node-&gt;length = (ulong)(max_bus - secondary_bus + 1);
+			dbg("found bus_node(base, length) = %x, %x\n", bus_node-&gt;base, bus_node-&gt;length);
+
+			if (!populated_slot) {
+				bus_node-&gt;next = ctrl-&gt;bus_head;
+				ctrl-&gt;bus_head = bus_node;
+			} else {
+				bus_node-&gt;next = func-&gt;bus_head;
+				func-&gt;bus_head = bus_node;
+			}
+		}
+
+#if link_available
+		++index;
+
+		while (index &lt; 8) {
+			if (((func = shpchp_slot_find(primary_bus, dev_func &gt;&gt; 3, index)) != NULL) &amp;&amp; populated_slot)
+				rc = link_available_resources(ctrl, func, index);
+			
+			if (rc)
+				break;
+
+			++index;
+		}
+#endif
+		i--;
+		one_slot += sizeof(struct slot_rt);
+	}
+
+	/* If all of the following fail, we don't have any resources for hot plug add */
+	rc = 1;
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;mem_head));
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;p_mem_head));
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;io_head));
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;bus_head));
+
+	return (rc);
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, 
+				func-&gt;device, func-&gt;function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &amp;command);
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;bcommand);
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_shpchprm_init_pci(void)
+{
+	shpchp_rom_start = (u8 *) ioremap(ROM_PHY_ADDR, ROM_PHY_LEN);
+	if (!shpchp_rom_start) {
+		err("Could not ioremap memory region for ROM\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_shpchprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff -puN /dev/null drivers/pci/hotplug/shpchprm_legacy.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchprm_legacy.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,113 @@
+/*
+ * SHPCHPRM Legacy: PHP Resource Manager for Non-ACPI/Legacy platform using HRT
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#ifndef _SHPCHPRM_LEGACY_H_
+#define _SHPCHPRM_LEGACY_H_
+
+#define ROM_PHY_ADDR	0x0F0000
+#define ROM_PHY_LEN	0x00FFFF
+
+struct slot_rt {
+	u8 dev_func;
+	u8 primary_bus;
+	u8 secondary_bus;
+	u8 max_bus;
+	u16 io_base;
+	u16 io_length;
+	u16 mem_base;
+	u16 mem_length;
+	u16 pre_mem_base;
+	u16 pre_mem_length;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug slot resource table registers based on the above structure layout */
+enum slot_rt_offsets {
+	DEV_FUNC = offsetof(struct slot_rt, dev_func),
+	PRIMARY_BUS = offsetof(struct slot_rt, primary_bus),
+	SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus),
+	MAX_BUS = offsetof(struct slot_rt, max_bus),
+	IO_BASE = offsetof(struct slot_rt, io_base),
+	IO_LENGTH = offsetof(struct slot_rt, io_length),
+	MEM_BASE = offsetof(struct slot_rt, mem_base),
+	MEM_LENGTH = offsetof(struct slot_rt, mem_length),
+	PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base),
+	PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length),
+};
+
+struct hrt {
+	char sig0;
+	char sig1;
+	char sig2;
+	char sig3;
+	u16 unused_IRQ;
+	u16 PCIIRQ;
+	u8 number_of_entries;
+	u8 revision;
+	u16 reserved1;
+	u32 reserved2;
+} __attribute__ ((packed));
+
+/* offsets to the hotplug resource table registers based on the above structure layout */
+enum hrt_offsets {
+	SIG0 = offsetof(struct hrt, sig0),
+	SIG1 = offsetof(struct hrt, sig1),
+	SIG2 = offsetof(struct hrt, sig2),
+	SIG3 = offsetof(struct hrt, sig3),
+	UNUSED_IRQ = offsetof(struct hrt, unused_IRQ),
+	PCIIRQ = offsetof(struct hrt, PCIIRQ),
+	NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries),
+	REVISION = offsetof(struct hrt, revision),
+	HRT_RESERVED1 = offsetof(struct hrt, reserved1),
+	HRT_RESERVED2 = offsetof(struct hrt, reserved2),
+};
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _SHPCHPRM_LEGACY_H_ */
diff -puN /dev/null drivers/pci/hotplug/shpchprm_nonacpi.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchprm_nonacpi.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,431 @@
+/*
+ * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/pci.h&gt;
+#include &lt;linux/init.h&gt;
+#include &lt;asm/uaccess.h&gt;
+#ifdef CONFIG_IA64
+#include &lt;asm/iosapic.h&gt;
+#endif
+#include "shpchp.h"
+#include "shpchprm.h"
+#include "shpchprm_nonacpi.h"
+
+void shpchprm_cleanup(void)
+{
+	return;
+}
+
+int shpchprm_print_pirt(void)
+{
+	return 0;
+}
+
+void * shpchprm_get_slot(struct slot *slot)
+{
+	return NULL;
+}
+
+int shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun, u8 busnum, u8 devnum)
+{
+	int	offset = devnum - ctrl-&gt;slot_device_offset;
+
+	dbg("%s: ctrl-&gt;slot_num_inc %d, offset %d\n", __FUNCTION__, ctrl-&gt;slot_num_inc, offset);
+	*sun = (u8) (ctrl-&gt;first_slot + ctrl-&gt;slot_num_inc * offset);
+	return 0;
+}
+
+static void print_pci_resource ( struct pci_resource	*aprh)
+{
+	struct pci_resource	*res;
+
+	for (res = aprh; res; res = res-&gt;next)
+		dbg("        base= 0x%x length= 0x%x\n", res-&gt;base, res-&gt;length);
+}
+
+
+static void phprm_dump_func_res( struct pci_func *fun)
+{
+	struct pci_func *func = fun;
+
+	if (func-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (func-&gt;bus_head);
+	}
+	if (func-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (func-&gt;io_head);
+	}
+	if (func-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (func-&gt;mem_head);
+	}
+	if (func-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (func-&gt;p_mem_head);
+	}
+}
+
+static int phprm_get_used_resources (
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	return shpchp_save_used_resources (ctrl, func, !DISABLE_CARD);
+}
+
+static int phprm_delete_resource(
+	struct pci_resource **aprh,
+	ulong base,
+	ulong size)
+{
+	struct pci_resource *res;
+	struct pci_resource *prevnode;
+	struct pci_resource *split_node;
+	ulong tbase;
+
+	shpchp_resource_sort_and_combine(aprh);
+
+	for (res = *aprh; res; res = res-&gt;next) {
+		if (res-&gt;base &gt; base)
+			continue;
+
+		if ((res-&gt;base + res-&gt;length) &lt; (base + size))
+			continue;
+
+		if (res-&gt;base &lt; base) {
+			tbase = base;
+
+			if ((res-&gt;length - (tbase - res-&gt;base)) &lt; size)
+				continue;
+
+			split_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base;
+			split_node-&gt;length = tbase - res-&gt;base;
+			res-&gt;base = tbase;
+			res-&gt;length -= split_node-&gt;length;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (res-&gt;length &gt;= size) {
+			split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+			if (!split_node)
+				return -ENOMEM;
+
+			split_node-&gt;base = res-&gt;base + size;
+			split_node-&gt;length = res-&gt;length - size;
+			res-&gt;length = size;
+
+			split_node-&gt;next = res-&gt;next;
+			res-&gt;next = split_node;
+		}
+
+		if (*aprh == res) {
+			*aprh = res-&gt;next;
+		} else {
+			prevnode = *aprh;
+			while (prevnode-&gt;next != res)
+				prevnode = prevnode-&gt;next;
+
+			prevnode-&gt;next = res-&gt;next;
+		}
+		res-&gt;next = NULL;
+		kfree(res);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int phprm_delete_resources(
+	struct pci_resource **aprh,
+	struct pci_resource *this
+	)
+{
+	struct pci_resource *res;
+
+	for (res = this; res; res = res-&gt;next)
+		phprm_delete_resource(aprh, res-&gt;base, res-&gt;length);
+
+	return 0;
+}
+
+
+static int configure_existing_function(
+	struct controller *ctrl,
+	struct pci_func *func
+	)
+{
+	int rc;
+
+	/* see how much resources the func has used. */
+	rc = phprm_get_used_resources (ctrl, func);
+
+	if (!rc) {
+		/* subtract the resources used by the func from ctrl resources */
+		rc  = phprm_delete_resources (&amp;ctrl-&gt;bus_head, func-&gt;bus_head);
+		rc |= phprm_delete_resources (&amp;ctrl-&gt;io_head, func-&gt;io_head);
+		rc |= phprm_delete_resources (&amp;ctrl-&gt;mem_head, func-&gt;mem_head);
+		rc |= phprm_delete_resources (&amp;ctrl-&gt;p_mem_head, func-&gt;p_mem_head);
+		if (rc)
+			warn("aCEF: cannot del used resources\n");
+	} else
+		err("aCEF: cannot get used resources\n");
+
+	return rc;
+}
+
+static int bind_pci_resources_to_slots ( struct controller *ctrl)
+{
+	struct pci_func *func;
+	int busn = ctrl-&gt;slot_bus;
+	int devn, funn;
+	u32	vid;
+
+	for (devn = 0; devn &lt; 32; devn++) {
+		for (funn = 0; funn &lt; 8; funn++) {
+			/*
+			if (devn == ctrl-&gt;device &amp;&amp; funn == ctrl-&gt;function)
+				continue;
+			 */
+			/* find out if this entry is for an occupied slot */
+			vid = 0xFFFFFFFF;
+
+			pci_bus_read_config_dword(ctrl-&gt;pci_dev-&gt;subordinate, PCI_DEVFN(devn, funn), PCI_VENDOR_ID, &amp;vid);
+
+			if (vid != 0xFFFFFFFF) {
+				func = shpchp_slot_find(busn, devn, funn);
+				if (!func)
+					continue;
+				configure_existing_function(ctrl, func);
+				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl-&gt;bus);
+				phprm_dump_func_res(func);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void phprm_dump_ctrl_res( struct controller *ctlr)
+{
+	struct controller *ctrl = ctlr;
+
+	if (ctrl-&gt;bus_head) {
+		dbg(":    BUS Resources:\n");
+		print_pci_resource (ctrl-&gt;bus_head);
+	}
+	if (ctrl-&gt;io_head) {
+		dbg(":    IO Resources:\n");
+		print_pci_resource (ctrl-&gt;io_head);
+	}
+	if (ctrl-&gt;mem_head) {
+		dbg(":    MEM Resources:\n");
+		print_pci_resource (ctrl-&gt;mem_head);
+	}
+	if (ctrl-&gt;p_mem_head) {
+		dbg(":    PMEM Resources:\n");
+		print_pci_resource (ctrl-&gt;p_mem_head);
+	}
+}
+
+/*
+ * phprm_find_available_resources
+ *
+ *  Finds available memory, IO, and IRQ resources for programming
+ *  devices which may be added to the system
+ *  this function is for hot plug ADD!
+ *
+ * returns 0 if success
+ */
+int shpchprm_find_available_resources(struct controller *ctrl)
+{
+	struct pci_func func;
+	u32 rc;
+
+	memset(&amp;func, 0, sizeof(struct pci_func));
+
+	func.bus = ctrl-&gt;bus;
+	func.device = ctrl-&gt;device;
+	func.function = ctrl-&gt;function;
+	func.is_a_board = 1;
+
+	/* Get resources for this PCI bridge */
+	rc = shpchp_save_used_resources (ctrl, &amp;func, !DISABLE_CARD);
+	dbg("%s: shpchp_save_used_resources rc = %d\n", __FUNCTION__, rc);
+
+	if (func.mem_head)
+		func.mem_head-&gt;next = ctrl-&gt;mem_head;
+	ctrl-&gt;mem_head = func.mem_head;
+
+	if (func.p_mem_head)
+		func.p_mem_head-&gt;next = ctrl-&gt;p_mem_head;
+	ctrl-&gt;p_mem_head = func.p_mem_head;
+
+	if (func.io_head)
+		func.io_head-&gt;next = ctrl-&gt;io_head;
+	ctrl-&gt;io_head = func.io_head;
+
+	if(func.bus_head)
+		func.bus_head-&gt;next = ctrl-&gt;bus_head;
+	ctrl-&gt;bus_head = func.bus_head;
+	if (ctrl-&gt;bus_head)
+		phprm_delete_resource(&amp;ctrl-&gt;bus_head, ctrl-&gt;pci_dev-&gt;subordinate-&gt;number, 1);
+
+	dbg("%s:pre-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl-&gt;bus);
+	phprm_dump_ctrl_res(ctrl);
+	bind_pci_resources_to_slots (ctrl);
+
+	dbg("%s:post-Bind PCI 0x%x Ctrl Resource Dump\n", __FUNCTION__, ctrl-&gt;bus);
+	phprm_dump_ctrl_res(ctrl);
+
+
+	/* If all of the following fail, we don't have any resources for hot plug add */
+	rc = 1;
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;mem_head));
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;p_mem_head));
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;io_head));
+	rc &amp;= shpchp_resource_sort_and_combine(&amp;(ctrl-&gt;bus_head));
+
+	return (rc);
+}
+
+int shpchprm_set_hpp(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8	card_type)
+{
+	u32 rc;
+	u8 temp_byte;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int	devfn;
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	temp_byte = 0x40;	/* hard coded value for LT */
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+		/* set subordinate Latency Timer */
+		rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte);
+
+		if (rc) {
+			dbg("%s: set secondary LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, 
+				func-&gt;device, func-&gt;function);
+			return rc;
+		}
+	}
+
+	/* set base Latency Timer */
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte);
+
+	if (rc) {
+		dbg("%s: set LT error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+		return rc;
+	}
+
+	/* set Cache Line size */
+	temp_byte = 0x08;	/* hard coded value for CLS */
+
+	rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte);
+
+	if (rc) {
+		dbg("%s: set CLS error. b:d:f(%02x:%02x:%02x)\n", __FUNCTION__, func-&gt;bus, func-&gt;device, func-&gt;function);
+	}
+
+	/* set enable_perr */
+	/* set enable_serr */
+
+	return rc;
+}
+
+void shpchprm_enable_card(
+	struct controller *ctrl,
+	struct pci_func *func,
+	u8 card_type)
+{
+	u16 command, bcommand;
+	struct pci_bus lpci_bus, *pci_bus;
+	unsigned int devfn;
+	int rc;
+
+	memcpy(&amp;lpci_bus, ctrl-&gt;pci_bus, sizeof(lpci_bus));
+	pci_bus = &amp;lpci_bus;
+	pci_bus-&gt;number = func-&gt;bus;
+	devfn = PCI_DEVFN(func-&gt;device, func-&gt;function);
+
+	rc = pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &amp;command);
+
+	command |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR
+		| PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+		| PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
+
+	rc = pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command);
+
+	if (card_type == PCI_HEADER_TYPE_BRIDGE) {
+
+		rc = pci_bus_read_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, &amp;bcommand);
+
+		bcommand |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR
+			| PCI_BRIDGE_CTL_NO_ISA;
+
+		rc = pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, bcommand);
+	}
+}
+
+static int legacy_shpchprm_init_pci(void)
+{
+	return 0;
+}
+
+int shpchprm_init(enum php_ctlr_type ctrl_type)
+{
+	int retval;
+
+	switch (ctrl_type) {
+	case PCI:
+		retval = legacy_shpchprm_init_pci();
+		break;
+	default:
+		retval = -ENODEV;
+		break;
+	}
+
+	return retval;
+}
diff -puN /dev/null drivers/pci/hotplug/shpchprm_nonacpi.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchprm_nonacpi.h	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,56 @@
+/*
+ * SHPCHPRM NONACPI: PHP Resource Manager for Non-ACPI/Legacy platform
+ *
+ * Copyright (C) 1995,2001 Compaq Computer Corporation
+ * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001 IBM Corp.
+ * Copyright (C) 2003-2004 Intel Corporation
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;, &lt;dely.l.sy@intel.com&gt;
+ *
+ */
+
+#ifndef _SHPCHPRM_NONACPI_H_
+#define _SHPCHPRM_NONACPI_H_
+
+struct irq_info {
+	u8 bus, devfn;		/* bus, device and function */
+	struct {
+		u8 link;	/* IRQ line ID, chipset dependent, 0=not routed */
+		u16 bitmap;	/* Available IRQs */
+	} __attribute__ ((packed)) irq[4];
+	u8 slot;		/* slot number, 0=onboard */
+	u8 rfu;
+} __attribute__ ((packed));
+
+struct irq_routing_table {
+	u32 signature;		/* PIRQ_SIGNATURE should be here */
+	u16 version;		/* PIRQ_VERSION */
+	u16 size;			/* Table size in bytes */
+	u8 rtr_bus, rtr_devfn;	/* Where the interrupt router lies */
+	u16 exclusive_irqs;	/* IRQs devoted exclusively to PCI usage */
+	u16 rtr_vendor, rtr_device;	/* Vendor and device ID of interrupt router */
+	u32 miniport_data;	/* Crap */
+	u8 rfu[11];
+	u8 checksum;		/* Modulo 256 checksum must give zero */
+	struct irq_info slots[0];
+} __attribute__ ((packed));
+
+#endif				/* _SHPCHPRM_NONACPI_H_ */
diff -puN /dev/null drivers/pci/hotplug/shpchp_sysfs.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/pci/hotplug/shpchp_sysfs.c	2004-02-19 23:22:45.000000000 -0800
@@ -0,0 +1,143 @@
+/*
+ * Compaq Hot Plug Controller Driver
+ *
+ * Copyright (c) 1995,2001 Compaq Computer Corporation
+ * Copyright (c) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Send feedback to &lt;greg@kroah.com&gt;
+ *
+ */
+
+#include &lt;linux/config.h&gt;
+#include &lt;linux/module.h&gt;
+#include &lt;linux/kernel.h&gt;
+#include &lt;linux/types.h&gt;
+#include &lt;linux/proc_fs.h&gt;
+#include &lt;linux/workqueue.h&gt;
+#include &lt;linux/pci.h&gt;
+#include "shpchp.h"
+
+
+/* A few routines that create sysfs entries for the hot plug controller */
+
+static int show_ctrl (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	out += sprintf(buf, "Free resources: memory\n");
+	index = 11;
+	res = ctrl-&gt;mem_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+	out += sprintf(out, "Free resources: prefetchable memory\n");
+	index = 11;
+	res = ctrl-&gt;p_mem_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+	out += sprintf(out, "Free resources: IO\n");
+	index = 11;
+	res = ctrl-&gt;io_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+	out += sprintf(out, "Free resources: bus numbers\n");
+	index = 11;
+	res = ctrl-&gt;bus_head;
+	while (res &amp;&amp; index--) {
+		out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+		res = res-&gt;next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
+
+static int show_dev (struct device *dev, char *buf)
+{
+	struct pci_dev *pci_dev;
+	struct controller *ctrl;
+	char * out = buf;
+	int index;
+	struct pci_resource *res;
+	struct pci_func *new_slot;
+	struct slot *slot;
+
+	pci_dev = container_of (dev, struct pci_dev, dev);
+	ctrl = pci_get_drvdata(pci_dev);
+
+	slot=ctrl-&gt;slot;
+
+	while (slot) {
+		new_slot = shpchp_slot_find(slot-&gt;bus, slot-&gt;device, 0);
+		if (!new_slot)
+			break;
+		out += sprintf(out, "assigned resources: memory\n");
+		index = 11;
+		res = new_slot-&gt;mem_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		out += sprintf(out, "assigned resources: prefetchable memory\n");
+		index = 11;
+		res = new_slot-&gt;p_mem_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		out += sprintf(out, "assigned resources: IO\n");
+		index = 11;
+		res = new_slot-&gt;io_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		out += sprintf(out, "assigned resources: bus numbers\n");
+		index = 11;
+		res = new_slot-&gt;bus_head;
+		while (res &amp;&amp; index--) {
+			out += sprintf(out, "start = %8.8x, length = %8.8x\n", res-&gt;base, res-&gt;length);
+			res = res-&gt;next;
+		}
+		slot=slot-&gt;next;
+	}
+
+	return out - buf;
+}
+static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL);
+
+void shpchp_create_ctrl_files (struct controller *ctrl)
+{
+	device_create_file (&amp;ctrl-&gt;pci_dev-&gt;dev, &amp;dev_attr_ctrl);
+	device_create_file (&amp;ctrl-&gt;pci_dev-&gt;dev, &amp;dev_attr_dev);
+}
diff -puN drivers/pci/msi.c~bk-pci drivers/pci/msi.c
--- 25/drivers/pci/msi.c~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/msi.c	2004-02-19 23:22:45.000000000 -0800
@@ -1,5 +1,9 @@
 /*
- * linux/drivers/pci/msi.c
+ * File:	msi.c
+ * Purpose:	PCI Message Signaled Interrupt (MSI)
+ *
+ * Copyright (C) 2003-2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
  */
 
 #include &lt;linux/mm.h&gt;
diff -puN drivers/pci/msi.h~bk-pci drivers/pci/msi.h
--- 25/drivers/pci/msi.h~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/msi.h	2004-02-19 23:22:45.000000000 -0800
@@ -1,6 +1,8 @@
 /*
- *	msi.h
+ * File:	msi.h
  *
+ * Copyright (C) 2003-2004 Intel
+ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
  */
 
 #ifndef MSI_H
diff -puN drivers/pci/pci.c~bk-pci drivers/pci/pci.c
--- 25/drivers/pci/pci.c~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/pci.c	2004-02-19 23:22:45.000000000 -0800
@@ -67,6 +67,39 @@ pci_max_busnr(void)
 	return max;
 }
 
+static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap)
+{
+	u16 status;
+	u8 pos, id;
+	int ttl = 48;
+
+	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &amp;status);
+	if (!(status &amp; PCI_STATUS_CAP_LIST))
+		return 0;
+
+	switch (hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+	case PCI_HEADER_TYPE_BRIDGE:
+		pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &amp;pos);
+		break;
+	case PCI_HEADER_TYPE_CARDBUS:
+		pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &amp;pos);
+		break;
+	default:
+		return 0;
+	}
+	while (ttl-- &amp;&amp; pos &gt;= 0x40) {
+		pos &amp;= ~3;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &amp;id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &amp;pos);
+	}
+	return 0;
+}
+
 /**
  * pci_find_capability - query for devices' capabilities 
  * @dev: PCI device to query
@@ -94,34 +127,7 @@ pci_max_busnr(void)
 int
 pci_find_capability(struct pci_dev *dev, int cap)
 {
-	u16 status;
-	u8 pos, id;
-	int ttl = 48;
-
-	pci_read_config_word(dev, PCI_STATUS, &amp;status);
-	if (!(status &amp; PCI_STATUS_CAP_LIST))
-		return 0;
-	switch (dev-&gt;hdr_type) {
-	case PCI_HEADER_TYPE_NORMAL:
-	case PCI_HEADER_TYPE_BRIDGE:
-		pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &amp;pos);
-		break;
-	case PCI_HEADER_TYPE_CARDBUS:
-		pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &amp;pos);
-		break;
-	default:
-		return 0;
-	}
-	while (ttl-- &amp;&amp; pos &gt;= 0x40) {
-		pos &amp;= ~3;
-		pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &amp;id);
-		if (id == 0xff)
-			break;
-		if (id == cap)
-			return pos;
-		pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &amp;pos);
-	}
-	return 0;
+	return __pci_bus_find_cap(dev-&gt;bus, dev-&gt;devfn, dev-&gt;hdr_type, cap);
 }
 
 /**
@@ -139,35 +145,11 @@ pci_find_capability(struct pci_dev *dev,
  */
 int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
 {
-	u16 status;
-	u8 pos, id;
-	int ttl = 48;
-	struct pci_dev *dev = bus-&gt;self;
+	u8 hdr_type;
 
-	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &amp;status);
-	if (!(status &amp; PCI_STATUS_CAP_LIST))
-		return 0;
-	switch (dev-&gt;hdr_type) {
-	case PCI_HEADER_TYPE_NORMAL:
-	case PCI_HEADER_TYPE_BRIDGE:
-		pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &amp;pos);
-		break;
-	case PCI_HEADER_TYPE_CARDBUS:
-		pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &amp;pos);
-		break;
-	default:
-		return 0;
-	}
-	while (ttl-- &amp;&amp; pos &gt;= 0x40) {
-		pos &amp;= ~3;
-		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &amp;id);
-		if (id == 0xff)
-			break;
-		if (id == cap)
-			return pos;
-		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &amp;pos);
-	}
-	return 0;
+	pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &amp;hdr_type);
+
+	return __pci_bus_find_cap(bus, devfn, hdr_type &amp; 0x7f, cap);
 }
 
 /**
diff -puN drivers/pci/quirks.c~bk-pci drivers/pci/quirks.c
--- 25/drivers/pci/quirks.c~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/pci/quirks.c	2004-02-19 23:22:45.000000000 -0800
@@ -703,9 +703,12 @@ static void __init asus_hides_smbus_host
 	    	case 0x8088: /* P4B533 */
 			asus_hides_smbus = 1;
 		}
-	if ((dev-&gt;device == PCI_DEVICE_ID_INTEL_82845G_HB) &amp;&amp;
-	    (dev-&gt;subsystem_device == 0x80b2)) /* P4PE */
-		asus_hides_smbus = 1;
+	if (dev-&gt;device == PCI_DEVICE_ID_INTEL_82845G_HB)
+		switch(dev-&gt;subsystem_device) {
+		case 0x80b2: /* P4PE */
+ 		case 0x8093: /* P4B533-V */
+			asus_hides_smbus = 1;
+		}
 	if ((dev-&gt;device == PCI_DEVICE_ID_INTEL_82850_HB) &amp;&amp;
 	    (dev-&gt;subsystem_device == 0x8030)) /* P4T533 */
 		asus_hides_smbus = 1;
diff -puN drivers/s390/Kconfig~bk-pci drivers/s390/Kconfig
--- 25/drivers/s390/Kconfig~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/drivers/s390/Kconfig	2004-02-19 23:22:45.000000000 -0800
@@ -164,25 +164,3 @@ config S390_TAPE_34XX
 	  It is safe to say "Y" here.
 
 endmenu
-
-
-config HOTPLUG
-	bool
-	default y
-	---help---
-	  Say Y here if you want to plug devices into your computer while
-	  the system is running, and be able to use them quickly.  In many
-	  cases, the devices can likewise be unplugged at any time too.
-
-	  One well known example of this is PCMCIA- or PC-cards, credit-card
-	  size devices such as network cards, modems or hard drives which are
-	  plugged into slots found on all modern laptop computers.  Another
-	  example, used on modern desktops as well as laptops, is USB.
-
-	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
-	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
-	  Then your kernel will automatically call out to a user mode "policy
-	  agent" (/sbin/hotplug) to load modules and set up software needed
-	  to use devices as you hotplug them.
-
-
diff -puN include/linux/pci.h~bk-pci include/linux/pci.h
--- 25/include/linux/pci.h~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/include/linux/pci.h	2004-02-19 23:22:45.000000000 -0800
@@ -362,8 +362,6 @@ enum pci_mmap_state {
 #define PCI_DMA_NONE		3
 
 #define DEVICE_COUNT_COMPATIBLE	4
-#define DEVICE_COUNT_IRQ	2
-#define DEVICE_COUNT_DMA	2
 #define DEVICE_COUNT_RESOURCE	12
 
 /*
diff -puN include/linux/pci_ids.h~bk-pci include/linux/pci_ids.h
--- 25/include/linux/pci_ids.h~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/include/linux/pci_ids.h	2004-02-19 23:22:45.000000000 -0800
@@ -1422,11 +1422,14 @@
 #define PCI_SUBVENDOR_ID_KEYSPAN	0x11a9
 #define PCI_SUBDEVICE_ID_KEYSPAN_SX2	0x5334
 
-#define PCI_VENDOR_ID_GALILEO		0x11ab
-#define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
-#define PCI_DEVICE_ID_GALILEO_GT64111	0x4146
-#define PCI_DEVICE_ID_GALILEO_GT96100	0x9652
-#define PCI_DEVICE_ID_GALILEO_GT96100A	0x9653
+#define PCI_VENDOR_ID_MARVELL		0x11ab
+#define PCI_DEVICE_ID_MARVELL_GT64011	0x4146
+#define PCI_DEVICE_ID_MARVELL_GT64111	0x4146
+#define PCI_DEVICE_ID_MARVELL_GT64260	0x6430
+#define PCI_DEVICE_ID_MARVELL_MV64360	0x6460
+#define PCI_DEVICE_ID_MARVELL_MV64460	0x6480
+#define PCI_DEVICE_ID_MARVELL_GT96100	0x9652
+#define PCI_DEVICE_ID_MARVELL_GT96100A	0x9653
 
 #define PCI_VENDOR_ID_LITEON		0x11ad
 #define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
diff -puN init/Kconfig~bk-pci init/Kconfig
--- 25/init/Kconfig~bk-pci	2004-02-19 23:22:41.000000000 -0800
+++ 25-akpm/init/Kconfig	2004-02-19 23:22:45.000000000 -0800
@@ -137,6 +137,25 @@ config LOG_BUF_SHIFT
 		     13 =&gt;  8 KB
 		     12 =&gt;  4 KB
 
+config HOTPLUG
+	bool "Support for hot-pluggable devices" if !ARCH_S390
+	default ARCH_S390
+	help
+	  Say Y here if you want to plug devices into your computer while
+	  the system is running, and be able to use them quickly.  In many
+	  cases, the devices can likewise be unplugged at any time too.
+
+	  One well known example of this is PCMCIA- or PC-cards, credit-card
+	  size devices such as network cards, modems or hard drives which are
+	  plugged into slots found on all modern laptop computers.  Another
+	  example, used on modern desktops as well as laptops, is USB.
+
+	  Enable HOTPLUG and KMOD, and build a modular kernel.  Get agent
+	  software (at &lt;http://linux-hotplug.sourceforge.net/&gt;) and install it.
+	  Then your kernel will automatically call out to a user mode "policy
+	  agent" (/sbin/hotplug) to load modules and set up software needed
+	  to use devices as you hotplug them.
+
 config IKCONFIG
 	bool "Kernel .config support"
 	---help---

_
</pre></body></html>