bk://kernel.bkbits.net/gregkh/linux/pci-2.6
lxiep@us.ibm.com|ChangeSet|20040612001538|61129 lxiep

# This is a BitKeeper generated diff -Nru style patch.
#
# drivers/pci/hotplug/rpaphp_vio.c
#   2004/06/08 15:53:59-07:00 lxiep@us.ibm.com +3 -3
#   PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
# 
# drivers/pci/hotplug/rpaphp_slot.c
#   2004/06/08 15:53:59-07:00 lxiep@us.ibm.com +113 -23
#   PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
# 
# drivers/pci/hotplug/rpaphp_pci.c
#   2004/06/08 15:53:59-07:00 lxiep@us.ibm.com +228 -100
#   PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
# 
# ChangeSet
#   2004/06/11 17:15:38-07:00 lxiep@us.ibm.com 
#   [PATCH] PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
#   
#   I made changes to rpaphp code, so it can handle multi-fuction
#   devices correctly. The problem is that the pci_dev field of slot struct
#   can only record one pci_dev of  the devices of a multi-fuction card.  I
#   changed pci_dev (a single pci_dev type pointer) to pci_funcs( a list of
#   pci_dev type pointers). I  rewrote some of the config/unconfig code to
#   support  the slot struct change.
#   
#   Along with above changes,  I added LDRSLOT(logical I/O slot) support.
#   We need LDRSLOT support for DLPAR I/O.  A card in a LDRSLOT can't be
#   physically removed, but can be logically removed  from one partiton and
#   reassinged to another partition.
#   
#   I also merged rpaphp changes from ames tree.
#   
#   
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/pci/hotplug/rpaphp_core.c
#   2004/06/08 15:53:59-07:00 lxiep@us.ibm.com +137 -62
#   PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
# 
# drivers/pci/hotplug/rpaphp.h
#   2004/06/08 15:53:59-07:00 lxiep@us.ibm.com +22 -6
#   PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
# 
# drivers/pci/hotplug/rpadlpar_core.c
#   2004/06/08 15:53:59-07:00 lxiep@us.ibm.com +5 -23
#   PCI Hotplug: rpaphp.patch -- multi-function devices not handled correctly
# 
# ChangeSet
#   2004/06/11 17:15:00-07:00 bjorn.helgaas@hp.com 
#   [PATCH] PCI: clarify pci.txt wrt IRQ allocation
#   
#   I think we should make it explicit that PCI IRQs shouldn't be relied
#   upon until after pci_enable_device().  This patch:
#   
#       ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.7-rc3/2.6.7-rc3-mm1/broken-out/bk-acpi.patch
#   
#   does PCI interrupt routing (based on ACPI _PRT) and IRQ allocation
#   at pci_enable_device()-time.
#   
#   (To avoid breaking things in 2.6, the above patch still allocates
#   all PCI IRQs in pci_acpi_init(), before any drivers are initialized.
#   But that shouldn't be needed by correct drivers, and I'd like to
#   remove it in 2.7.)
#   
#   
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# Documentation/pci.txt
#   2004/06/11 14:09:58-07:00 bjorn.helgaas@hp.com +3 -2
#   PCI: clarify pci.txt wrt IRQ allocation
# 
# ChangeSet
#   2004/06/08 21:55:31-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.6
#   into bix.(none):/usr/src/bk-pci
# 
# arch/i386/kernel/dmi_scan.c
#   2004/06/08 21:55:27-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/08 14:28:46-07:00 daniel.ritz@gmx.ch 
#   [PATCH] PCI: fix irq routing on acer travelmate 360 laptop
#   
#   Fixes interrupt routing on acer travelmate 360 notebooks.  it looks like
#   the bios assigned the wrong pirq value for the cardbus bridge.  just
#   assigning irq 10 to all devices with pirq 0x63 would break second usb port.
#   pirq 0x68 seems to be right one for cardbus.
#   
#   Signed-off-by: Daniel Ritz <daniel.ritz@gmx.ch>
#   Signed-off-by: Andrew Morton <akpm@osdl.org>
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# arch/i386/pci/irq.c
#   2004/06/05 00:16:53-07:00 daniel.ritz@gmx.ch +9 -0
#   PCI: fix irq routing on acer travelmate 360 laptop
# 
# arch/i386/kernel/dmi_scan.c
#   2004/06/05 00:16:53-07:00 daniel.ritz@gmx.ch +29 -0
#   PCI: fix irq routing on acer travelmate 360 laptop
# 
# ChangeSet
#   2004/06/04 15:01:07-07:00 dlsy@snoqualmie.dp.intel.com 
#   [PATCH] Fixes for hot-plug drivers (updated)
#   
#   Here is the updated patch (against 2.6.7-rc1) for the shpchp and pciehp
#   drivers that fixes the following issues:
#   - proper LED status when latch is open or card is not present while the
#     user tries to power up the slot; (reported by D. Keck)
#   - check if kmalloc() return NULL before proceeding in acpi_get__hpp();
#     (provided by L. Capitulino)
#   - add up(&ctrl->crit_sect) before return in error cases in several
#     places;
#   - proper handling of resources when there are other onboard devices
#     behind the p2p bridge that has the hot-plug capabaility;
#   - need to check negotiated link width in check_lnk_status();
#   - cleanup board_added() in pciehp
#   
#   
#   Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
# 
# drivers/pci/hotplug/shpchprm_nonacpi.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +13 -5
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/shpchprm_acpi.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +17 -5
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/shpchp_pci.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +1 -0
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/shpchp_ctrl.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +23 -37
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/shpchp.h
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +1 -0
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/pciehprm_nonacpi.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +13 -5
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/pciehprm_acpi.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +17 -5
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/pciehp_hpc.c
#   2004/06/02 11:59:48-07:00 dlsy@snoqualmie.dp.intel.com +3 -1
#   Fixes for hot-plug drivers (updated)
# 
# drivers/pci/hotplug/pciehp_ctrl.c
#   2004/06/02 17:04:06-07:00 dlsy@snoqualmie.dp.intel.com +49 -98
#   Fixes for hot-plug drivers (updated)
# 
# ChangeSet
#   2004/06/03 10:37:43-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci
# 
# include/linux/pci_ids.h
#   2004/06/03 10:37:40-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/06/02 13:31:47-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci
# 
# include/linux/pci_ids.h
#   2004/06/02 13:31:44-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/28 14:10:25-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.6
#   into bix.(none):/usr/src/bk-pci
# 
# include/linux/pci_ids.h
#   2004/05/28 14:10:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# drivers/pci/pci.ids
#   2004/05/28 14:10:22-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/28 14:09:37-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci
# 
# include/linux/pci_ids.h
#   2004/05/28 14:09:34-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/24 11:42:00-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci
# 
# include/linux/pci_ids.h
#   2004/05/24 11:41:57-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/22 23:42:26-07:00 akpm@bix.(none) 
#   Merge bix.(none):/usr/src/bk25 into bix.(none):/usr/src/bk-pci
# 
# include/linux/pci_ids.h
#   2004/05/22 23:42:23-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2004/05/19 14:16:27-07:00 akpm@bix.(none) 
#   Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.6
#   into bix.(none):/usr/src/bk-pci
# 
# drivers/pci/pci.ids
#   2004/05/19 14:16:24-07:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
diff -Nru a/Documentation/pci.txt b/Documentation/pci.txt
--- a/Documentation/pci.txt	2004-06-14 00:00:16 -07:00
+++ b/Documentation/pci.txt	2004-06-14 00:00:16 -07:00
@@ -166,8 +166,9 @@
 ~~~~~~~~~~~~~~~~~~~
    Before you do anything with the device you've found, you need to enable
 it by calling pci_enable_device() which enables I/O and memory regions of
-the device, assigns missing resources if needed and wakes up the device
-if it was in suspended state. Please note that this function can fail.
+the device, allocates an IRQ if necessary, assigns missing resources if
+needed and wakes up the device if it was in suspended state. Please note
+that this function can fail.
 
    If you want to use the device in bus mastering mode, call pci_set_master()
 which enables the bus master bit in PCI_COMMAND register and also fixes
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	2004-06-14 00:00:16 -07:00
+++ b/arch/i386/kernel/dmi_scan.c	2004-06-14 00:00:16 -07:00
@@ -360,6 +360,21 @@
 }
 
 /*
+ * Work around broken Acer TravelMate 360 Notebooks which assign Cardbus to
+ * IRQ 11 even though it is actually wired to IRQ 10
+ */
+static __init int fix_acer_tm360_irqrouting(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+	extern int acer_tm360_irqrouting;
+	if (acer_tm360_irqrouting == 0) {
+		acer_tm360_irqrouting = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+#endif
+	return 0;
+}
+/*
  *  Check for clue free BIOS implementations who use
  *  the following QA technique
  *
@@ -845,6 +860,13 @@
 			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
 			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
 			} },
+
+	{ fix_acer_tm360_irqrouting, "Acer TravelMate 36x Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Acer"),
+			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+			NO_MATCH, NO_MATCH
+			} },
+
  
 
 	/*
@@ -1034,6 +1056,13 @@
 			MATCH(DMI_BOARD_NAME, "PR-DLS"),
 			MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
 			MATCH(DMI_BIOS_DATE, "03/21/2003") }},
+
+ 	{ disable_acpi_pci, "Acer TravelMate 36x Laptop", {
+ 			MATCH(DMI_SYS_VENDOR, "Acer"),
+ 			MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+ 			NO_MATCH, NO_MATCH
+ 			} },
+
 #endif
 
 	{ NULL, }
diff -Nru a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
--- a/arch/i386/pci/irq.c	2004-06-14 00:00:16 -07:00
+++ b/arch/i386/pci/irq.c	2004-06-14 00:00:16 -07:00
@@ -23,6 +23,7 @@
 #define PIRQ_VERSION 0x0100
 
 int broken_hp_bios_irq9;
+int acer_tm360_irqrouting;
 
 static struct irq_routing_table *pirq_table;
 
@@ -743,6 +744,14 @@
 		dev->irq = 11;
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
 		r->set(pirq_router_dev, dev, pirq, 11);
+	}
+
+	/* same for Acer Travelmate 360, but with CB and irq 11 -> 10 */
+	if (acer_tm360_irqrouting && dev->irq == 11 && dev->vendor == PCI_VENDOR_ID_O2) {
+		pirq = 0x68;
+		mask = 0x400;
+		dev->irq = r->get(pirq_router_dev, dev, pirq);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
 	}
 
 	/*
diff -Nru a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
--- a/drivers/pci/hotplug/pciehp_ctrl.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/pciehp_ctrl.c	2004-06-14 00:00:16 -07:00
@@ -1058,6 +1058,34 @@
    hotplug controller logic
  */
 
+static void set_slot_off(struct controller *ctrl, struct slot * pslot)
+{
+	/* Wait for exclusive access to hardware */
+	down(&ctrl->crit_sect);
+
+	/* turn off slot, turn on Amber LED, turn off Green LED */
+	if (pslot->hpc_ops->power_off_slot(pslot)) {   
+		err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
+		return;
+	}
+	wait_for_ctrl_irq (ctrl);
+
+	pslot->hpc_ops->green_led_off(pslot);   
+	
+	wait_for_ctrl_irq (ctrl);
+
+	/* turn on Amber LED */
+	if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
+		err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
+		return;
+	}
+	wait_for_ctrl_irq (ctrl);
+
+	/* Done with exclusive hardware access */
+	up(&ctrl->crit_sect);
+}
 
 /**
  * board_added - Called after a board has been added to the system.
@@ -1071,7 +1099,7 @@
 	u8 hp_slot;
 	int index;
 	u32 temp_register = 0xFFFFFFFF;
-	u32 retval, rc = 0;
+	u32 rc = 0;
 	struct pci_func *new_func = NULL;
 	struct slot *p_slot;
 	struct resource_lists res_lists;
@@ -1086,8 +1114,10 @@
 
 	/* Power on slot */
 	rc = p_slot->hpc_ops->power_on_slot(p_slot);
-	if (rc)
+	if (rc) {
+		up(&ctrl->crit_sect);
 		return -1;
+	}
 
 	/* Wait for the command to complete */
 	wait_for_ctrl_irq (ctrl);
@@ -1105,11 +1135,12 @@
 	wait_for_ctrl_irq (ctrl);
 	dbg("%s: afterlong_delay\n", __FUNCTION__);
 
-	/*  Make this to check for link training status */
+	/*  Check link training status */
 	rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
 	if (rc) {
 		err("%s: Failed to check link status\n", __FUNCTION__);
-		return -1;
+		set_slot_off(ctrl, p_slot);
+		return rc;
 	}
 
 	dbg("%s: func status = %x\n", __FUNCTION__, func->status);
@@ -1159,36 +1190,7 @@
 		pciehp_resource_sort_and_combine(&(ctrl->bus_head));
 
 		if (rc) {
-			/* Wait for exclusive access to hardware */
-			down(&ctrl->crit_sect);
-
-			/* turn off slot, turn on Amber LED, turn off Green LED */
-			retval = p_slot->hpc_ops->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->hpc_ops->green_led_off(p_slot);   
-			
-			/* Wait for the command to complete */
-			wait_for_ctrl_irq (ctrl);
-
-			/* turn on Amber LED */
-			retval = p_slot->hpc_ops->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(&ctrl->crit_sect);
-
+			set_slot_off(ctrl, p_slot);
 			return rc;
 		}
 		pciehp_save_slot_config(ctrl, func);
@@ -1223,37 +1225,8 @@
 		up(&ctrl->crit_sect);
 
 	} else {
-		/* Wait for exclusive access to hardware */
-		down(&ctrl->crit_sect);
-
-		/* turn off slot, turn on Amber LED, turn off Green LED */
-		retval = p_slot->hpc_ops->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->hpc_ops->green_led_off(p_slot);   
-		
-		/* Wait for the command to complete */
-		wait_for_ctrl_irq (ctrl);
-
-		/* turn on Amber LED */
-		retval = p_slot->hpc_ops->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(&ctrl->crit_sect);
-
-		return rc;
+		set_slot_off(ctrl, p_slot);
+		return -1;
 	}
 	return 0;
 }
@@ -1320,6 +1293,7 @@
 	rc = p_slot->hpc_ops->power_off_slot(p_slot);
 	if (rc) {
 		err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
+		up(&ctrl->crit_sect);
 		return rc;
 	}
 	/* Wait for the command to complete */
@@ -1406,7 +1380,6 @@
 {
 	struct slot *p_slot = (struct slot *) slot;
 	u8 getstatus;
-	int rc;
 	
 	pushbutton_pending = 0;
 
@@ -1420,23 +1393,7 @@
 		p_slot->state = POWEROFF_STATE;
 		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
 
-		if (pciehp_disable_slot(p_slot)) {
-			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
-
-			/* Turn on the Attention LED */
-			rc = p_slot->hpc_ops->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->ctrl);
-
-			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
-		}
+		pciehp_disable_slot(p_slot);
 		p_slot->state = STATIC_STATE;
 	} else {
 		p_slot->state = POWERON_STATE;
@@ -1446,15 +1403,6 @@
 			/* Wait for exclusive access to hardware */
 			down(&p_slot->ctrl->crit_sect);
 
-			/* Turn off the green LED */
-			rc = p_slot->hpc_ops->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->ctrl);
-			
 			p_slot->hpc_ops->green_led_off(p_slot);
 
 			/* Wait for the command to complete */
@@ -1664,7 +1612,10 @@
 					down(&ctrl->crit_sect);
 
 					p_slot->hpc_ops->set_attention_status(p_slot, 1);
+					wait_for_ctrl_irq (ctrl);
+						
 					p_slot->hpc_ops->green_led_off(p_slot);
+					wait_for_ctrl_irq (ctrl);
 
 					/* Done with exclusive hardware access */
 					up(&ctrl->crit_sect);
@@ -1701,21 +1652,21 @@
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	
 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	
 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
@@ -1788,21 +1739,21 @@
 	if (ret || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 
 	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (ret || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 
 	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (ret || !getstatus) {
 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return 0;
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
diff -Nru a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
--- a/drivers/pci/hotplug/pciehp_hpc.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/pciehp_hpc.c	2004-06-14 00:00:16 -07:00
@@ -349,7 +349,9 @@
 		return retval;
 	}
 
-	if ( (lnk_status & (LNK_TRN | LNK_TRN_ERR)) == 0x0C00) {
+	dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
+	if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || 
+		!(lnk_status & NEG_LINK_WD)) {
 		err("%s : Link Training Error occurs \n", __FUNCTION__);
 		retval = -1;
 		return retval;
diff -Nru a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c
--- a/drivers/pci/hotplug/pciehprm_acpi.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/pciehprm_acpi.c	2004-06-14 00:00:16 -07:00
@@ -218,6 +218,10 @@
 	}
 
 	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	if (!ab->_hpp) {
+		err ("acpi_pciehprm:%s alloc for _HPP failed\n", path_name);
+		goto free_and_return;
+	}
 	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
 
 	ab->_hpp->cache_line_size	= nui[0];
@@ -1393,7 +1397,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->slot_bus;
 	int devn, funn;
 	u32	vid;
@@ -1411,11 +1415,19 @@
 			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);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					pciehprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					pciehprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				pciehprm_dump_func_res(func);
 			}
 		}
 	}
diff -Nru a/drivers/pci/hotplug/pciehprm_nonacpi.c b/drivers/pci/hotplug/pciehprm_nonacpi.c
--- a/drivers/pci/hotplug/pciehprm_nonacpi.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/pciehprm_nonacpi.c	2004-06-14 00:00:16 -07:00
@@ -276,7 +276,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->slot_bus;
 	int devn, funn;
 	u32	vid;
@@ -297,11 +297,19 @@
 				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);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					phprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					phprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				phprm_dump_func_res(func);
 			}
 		}
 	}
diff -Nru a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
--- a/drivers/pci/hotplug/rpadlpar_core.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/rpadlpar_core.c	2004-06-14 00:00:16 -07:00
@@ -24,25 +24,6 @@
 
 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 *) &drc_names[1];
-
-	return ptr;
-}
-
 static struct device_node *find_php_slot_vio_node(char *drc_name)
 {
 	struct device_node *child;
@@ -53,9 +34,9 @@
 		return NULL;
 
 	for (child = of_get_next_child(parent, NULL);
-	     child; child = of_get_next_child(parent, child)) {
+		child; child = of_get_next_child(parent, child)) {
 		loc_code = get_property(child, "ibm,loc-code", NULL);
-		if (loc_code && !strcmp(loc_code, drc_name))
+		if (loc_code && !strncmp(loc_code, drc_name, strlen(drc_name)))
 			return child;
 	}
 
@@ -69,7 +50,7 @@
 
 	while ((np = of_find_node_by_type(np, "pci")))
 		if (is_hotplug_capable(np)) {
-			name = get_node_drc_name(np);
+			name = rpaphp_get_drc_name(np);
 			if (name && (!strcmp(drc_name, name)))
 				break;
 		}
@@ -324,6 +305,7 @@
 	}
 
 	/* Remove pci bus */
+
 	if (dlpar_pci_remove_bus(bridge_dev)) {
 		printk(KERN_ERR "%s: unable to remove pci bus %s\n",
 			__FUNCTION__, drc_name);
@@ -364,7 +346,7 @@
 		rc = -EINVAL;
 		goto exit;
 	}
-
+	
 	switch (slot->dev_type) {
 		case PCI_DEV:
 			rc = dlpar_remove_pci_slot(slot, drc_name);
diff -Nru a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
--- a/drivers/pci/hotplug/rpaphp.h	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/rpaphp.h	2004-06-14 00:00:16 -07:00
@@ -30,6 +30,9 @@
 #include <linux/pci.h>
 #include "pci_hotplug.h"
 
+#define	HOTPLUG	1
+#define	EMBEDDED 0
+
 #define DR_INDICATOR 9002
 #define DR_ENTITY_SENSE 9003
 
@@ -73,6 +76,11 @@
 #define	CONFIGURED	1
 #define	EMPTY		0
 
+struct rpaphp_pci_func {
+	struct pci_dev *pci_dev;
+	struct list_head sibling;
+};
+
 /*
  * struct slot - slot information for each *physical* slot
  */
@@ -83,14 +91,13 @@
 	u32 power_domain;
 	char *name;
 	char *location;
+	u8 removable;
 	struct device_node *dn;	/* slot's device_node in OFDT */
-	/* dn has phb info */
+				/* dn has phb info */
 	struct pci_dev *bridge;	/* slot's pci_dev in pci_devices */
 	union {
-		struct pci_dev *pci_dev;	/* pci_dev of device in this slot */
-		/* it will be used for unconfig */
-		/* NULL if slot is empty */
-		struct vio_dev *vio_dev;	/* vio_dev of the device in this slot */
+		struct list_head pci_funcs; /* pci_devs in PCI slot */ 
+		struct vio_dev *vio_dev; /* vio_dev in VIO slot */
 	} dev;
 	u8 dev_type;		/* VIO or PCI */
 	struct hotplug_slot *hotplug_slot;
@@ -101,6 +108,13 @@
 extern struct list_head rpaphp_slot_head;
 extern int num_slots;
 
+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);
+}
+
 /* function prototypes */
 
 /* rpaphp_pci.c */
@@ -110,10 +124,12 @@
 extern int register_pci_slot(struct slot *slot);
 extern int rpaphp_unconfig_pci_adapter(struct slot *slot);
 extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev);
 
 /* rpaphp_core.c */
 extern int rpaphp_add_slot(struct device_node *dn);
 extern int rpaphp_remove_slot(struct slot *slot);
+extern char *rpaphp_get_drc_name(struct device_node *dn);
 
 /* rpaphp_vio.c */
 extern int rpaphp_get_vio_adapter_status(struct slot *slot, int is_init, u8 * value);
@@ -125,8 +141,8 @@
 extern void dealloc_slot_struct(struct slot *slot);
 extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
 extern int register_slot(struct slot *slot);
+extern int deregister_slot(struct slot *slot);
 extern int rpaphp_get_power_status(struct slot *slot, u8 * value);
 extern int rpaphp_set_attention_status(struct slot *slot, u8 status);
-extern void rpaphp_sysfs_remove_attr_location(struct hotplug_slot *slot);
 	
 #endif				/* _PPC64PHP_H */
diff -Nru a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
--- a/drivers/pci/hotplug/rpaphp_core.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/rpaphp_core.c	2004-06-14 00:00:16 -07:00
@@ -54,6 +54,8 @@
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
+void eeh_register_disable_func(int (*)(struct pci_dev *));
+
 module_param(debug, bool, 0644);
 
 static int enable_slot(struct hotplug_slot *slot);
@@ -63,6 +65,7 @@
 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 rpaphp_disable_slot(struct pci_dev *dev);
 
 struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
 	.owner = THIS_MODULE,
@@ -89,7 +92,7 @@
  */
 static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
 {
-	int retval;
+	int retval = 0;
 	struct slot *slot = (struct slot *)hotplug_slot->private;
 
 	down(&rpaphp_sem);
@@ -208,47 +211,53 @@
 
 int rpaphp_remove_slot(struct slot *slot)
 {
-	int retval = 0;
-	struct hotplug_slot *php_slot = slot->hotplug_slot;
-
-	list_del(&slot->rpaphp_slot_list);
-	
-	/* remove "php_location" file */
-	rpaphp_sysfs_remove_attr_location(php_slot);
-
-	retval = pci_hp_deregister(php_slot);
-	if (retval)
-		err("Problem unregistering a slot %s\n", slot->name);
-
-	num_slots--;
-
-	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
-	return retval;
+	return deregister_slot(slot);
 }
 
-static int is_php_dn(struct device_node *dn, int **indexes, int **names, int **types,
-	  int **power_domains)
+static int get_dn_properties(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;
+
 	/* &names[1] contains NULL terminated slot names */
 	*names = (int *) get_property(dn, "ibm,drc-names", NULL);
-	if (!*names)
-		return 0;
+
 	/* &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 (strcmp(dn->name, "pci") == 0 &&
-			!get_property(dn, "ibm,fw-pci-hot-plug-ctrl", NULL))
-		return 0;
-	return 1;
+	*power_domains = (int *) get_property(dn, "ibm,drc-power-domains", NULL);
+	
+	if (*indexes && *names && *types && *power_domains) 
+		return (1);
+	
+	return (0);
+}
+
+static int is_php_dn(struct device_node *dn, int **indexes, int **names, int **types,
+	  int **power_domains)
+{
+	if (!is_hotplug_capable(dn))
+		return (0);
+	if (!get_dn_properties(dn, indexes, names, types, power_domains))
+		return (0);
+	return (1);
+}
+
+static int is_dr_dn(struct device_node *dn, int **indexes, int **names, int **types,
+	  int **power_domains, int **my_drc_index)
+{
+	if (!is_hotplug_capable(dn))
+		return (0);
+
+	*my_drc_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
+	if(!*my_drc_index) 		
+		return (0);
+
+	if (!dn->parent)
+		return (0);
+
+	return get_dn_properties(dn->parent, indexes, names, types, power_domains);
 }
 
 static inline int is_vdevice_root(struct device_node *dn)
@@ -256,15 +265,48 @@
 	return !strcmp(dn->name, "vdevice");
 }
 
-/**
- * rpaphp_add_slot: Add  Hot Plug slot(s) to sysfs
- *
- */
+char *rpaphp_get_drc_name(struct device_node *dn)
+{
+	char *name, *ptr = NULL;
+	int *drc_names, *drc_indexes, i;
+	struct device_node *parent = dn->parent;	
+	u32 *my_drc_index;
+
+	if (!parent)
+		return NULL;
+
+	my_drc_index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL);
+	if (!my_drc_index)
+		return NULL;	
+
+	drc_names = (int *) get_property(parent, "ibm,drc-names", NULL);
+	drc_indexes = (int *) get_property(parent, "ibm,drc-indexes", NULL);
+	if (!drc_names || !drc_indexes)
+		return NULL;
+
+	name = (char *) &drc_names[1];
+	for (i = 0; i < drc_indexes[0]; i++, name += (strlen(name) + 1)) {
+		if (drc_indexes[i + 1] == *my_drc_index) {
+			ptr = (char *) name;
+			break;
+		}
+	}
+
+	return ptr;
+}
+
+/****************************************************************
+ *	rpaphp not only registers PCI hotplug slots(HOTPLUG), 
+ *	but also logical DR slots(EMBEDDED).
+ *	HOTPLUG slot: An adapter can be physically added/removed. 
+ *	EMBEDDED slot: An adapter can be logically removed/added
+ *		  from/to a partition with the slot.
+ ***************************************************************/
 int rpaphp_add_slot(struct device_node *dn)
 {
 	struct slot *slot;
 	int retval = 0;
-	int i;
+	int i, *my_drc_index, slot_type;
 	int *indexes, *names, *types, *power_domains;
 	char *name, *type;
 
@@ -277,42 +319,65 @@
 	}
 
 	/* register PCI devices */
-	if (dn->name != 0 && strcmp(dn->name, "pci") == 0 &&
-	    is_php_dn(dn, &indexes, &names, &types, &power_domains)) {
+	if (dn->name != 0 && strcmp(dn->name, "pci") == 0) {
+		if (is_php_dn(dn, &indexes, &names, &types, &power_domains))  
+			slot_type = HOTPLUG;
+		else if (is_dr_dn(dn, &indexes, &names, &types, &power_domains, &my_drc_index)) 
+			slot_type = EMBEDDED;
+		else goto exit;
 
 		name = (char *) &names[1];
 		type = (char *) &types[1];
-		for (i = 0; i < indexes[0];
-					i++,
-					name += (strlen(name) + 1),
-					type += (strlen(type) + 1)) {
-			if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
-						       power_domains[i + 1]))) {
-				retval = -ENOMEM;
-				goto exit;
-			}
-			slot->type = simple_strtoul(type, NULL, 10);
-			if (slot->type < 1 || slot->type > 16)
-				slot->type = 0;
-			retval = register_pci_slot(slot);
+		for (i = 0; i < indexes[0]; i++,
+	     		name += (strlen(name) + 1), type += (strlen(type) + 1)) {
 
-		}		/* for indexes */
-	}			/* end of PCI device_node */
+			if ( slot_type == HOTPLUG || 
+				(slot_type == EMBEDDED && indexes[i + 1] == my_drc_index[0])) {
+				
+				if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
+					       power_domains[i + 1]))) {
+					retval = -ENOMEM;
+					goto exit;
+				}
+				if (slot_type == EMBEDDED)
+					slot->type = EMBEDDED;
+				else
+					slot->type = simple_strtoul(type, NULL, 10);
+				
+				dbg("    Found drc-index:0x%x drc-name:%s drc-type:%s\n",
+					indexes[i + 1], name, type);
+
+				retval = register_pci_slot(slot);
+				if (slot_type == EMBEDDED)
+					goto exit;
+			}
+		}
+	}
 exit:
 	dbg("%s - Exit: num_slots=%d rc[%d]\n",
 	    __FUNCTION__, num_slots, retval);
 	return retval;
 }
 
-static int __init init_rpa(void)
+/*
+ * init_slots - initialize 'struct slot' structures for each slot
+ *
+ */
+static void init_slots(void)
 {
 	struct device_node *dn;
 
+	for (dn = find_all_nodes(); dn; dn = dn->next)
+		rpaphp_add_slot(dn);
+}
+
+static int __init init_rpa(void)
+{
+
 	init_MUTEX(&rpaphp_sem);
 
 	/* initialize internal data structure etc. */
-	for (dn = find_all_nodes(); dn; dn = dn->next)
-		rpaphp_add_slot(dn);
+	init_slots();
 	if (!num_slots)
 		return -ENODEV;
 
@@ -342,12 +407,18 @@
 {
 	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
+	/* let EEH know they can use hotplug */
+	eeh_register_disable_func(&rpaphp_disable_slot);
+
 	/* read all the PRA info from the system */
 	return init_rpa();
 }
 
 static void __exit rpaphp_exit(void)
 {
+	/* let EEH know we are going away */
+	eeh_register_disable_func(NULL);
+
 	cleanup_slots();
 }
 
@@ -374,11 +445,16 @@
 		retval = -EINVAL;
 	}
 	up(&rpaphp_sem);
-      exit:
+exit:
 	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
 }
 
+static int rpaphp_disable_slot(struct pci_dev *dev)
+{
+	return disable_slot(rpaphp_find_hotplug_slot(dev));
+}
+
 static int disable_slot(struct hotplug_slot *hotplug_slot)
 {
 	int retval;
@@ -395,9 +471,7 @@
 	down(&rpaphp_sem);
 	switch (slot->dev_type) {
 	case PCI_DEV:
-		rpaphp_set_attention_status(slot, LED_ID);
 		retval = rpaphp_unconfig_pci_adapter(slot);
-		rpaphp_set_attention_status(slot, LED_OFF);
 		break;
 	case VIO_DEV:
 		retval = rpaphp_unconfig_vio_adapter(slot);
@@ -406,7 +480,7 @@
 		retval = -ENODEV;
 	}
 	up(&rpaphp_sem);
-      exit:
+exit:
 	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
 }
@@ -417,3 +491,4 @@
 EXPORT_SYMBOL_GPL(rpaphp_add_slot);
 EXPORT_SYMBOL_GPL(rpaphp_remove_slot);
 EXPORT_SYMBOL_GPL(rpaphp_slot_head);
+EXPORT_SYMBOL_GPL(rpaphp_get_drc_name);
diff -Nru a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
--- a/drivers/pci/hotplug/rpaphp_pci.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/rpaphp_pci.c	2004-06-14 00:00:16 -07:00
@@ -30,24 +30,18 @@
 
 struct pci_dev *rpaphp_find_pci_dev(struct device_node *dn)
 {
-	struct pci_dev *retval_dev = NULL, *dev;
+	struct pci_dev *retval_dev = NULL, *dev = NULL;
 	char bus_id[BUS_ID_SIZE];
 
 	sprintf(bus_id, "%04x:%02x:%02x.%d",dn->phb->global_number,
 		dn->busno, PCI_SLOT(dn->devfn), PCI_FUNC(dn->devfn));
-
-	dbg("Enter rpaphp_find_pci_dev() full_name=%s bus_id=%s\n", 
-		dn->full_name, bus_id);
-	
 	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               if (!strcmp(pci_name(dev), bus_id)) {
+		if (!strcmp(pci_name(dev), bus_id)) {
 			retval_dev = dev;
-			dbg("rpaphp_find_pci_dev(): found dev=%p\n\n", dev);
 			break;
 		}
 	}
 	return retval_dev;
-
 }
 
 EXPORT_SYMBOL_GPL(rpaphp_find_pci_dev);
@@ -79,11 +73,6 @@
 	return rpaphp_find_pci_dev(slot->dn);
 }
 
-static struct pci_dev *rpaphp_find_adapter_pdev(struct slot *slot)
-{
-	return rpaphp_find_pci_dev(slot->dn->child);
-}
-
 static int rpaphp_get_sensor_state(struct slot *slot, int *state)
 {
 	int rc;
@@ -144,7 +133,8 @@
 			else if (rpaphp_find_pci_dev(slot->dn->child))
 				*value = CONFIGURED;
 			else {
-				dbg("%s: can't find pdev of adapter in slot[%s]\n", __FUNCTION__, slot->name);
+				err("%s: can't find pdev of adapter in slot[%s]\n", 
+					__FUNCTION__, slot->dn->full_name);
 				*value = NOT_CONFIGURED;
 			}
 		}
@@ -158,7 +148,8 @@
 }
 
 /* Must be called before pci_bus_add_devices */
-static void rpaphp_fixup_new_pci_devices(struct pci_bus *bus)
+static void 
+rpaphp_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
 {
 	struct pci_dev *dev;
 
@@ -169,8 +160,9 @@
 		 */
 		if (list_empty(&dev->global_list)) {
 			int i;
-
-			pcibios_fixup_device_resources(dev, bus);
+			
+			if(fix_bus)
+				pcibios_fixup_device_resources(dev, bus);
 			pci_read_irq_line(dev);
 			for (i = 0; i < PCI_NUM_RESOURCES; i++) {
 				struct resource *r = &dev->resource[i];
@@ -183,69 +175,139 @@
 	}
 }
 
-static void
-rpaphp_pci_config_device(struct pci_bus *pci_bus, struct device_node *dn)
-{
-	int num;
-
-	num = pci_scan_slot(pci_bus, PCI_DEVFN(PCI_SLOT(dn->devfn), 0));
-	if (num) {
-		rpaphp_fixup_new_pci_devices(pci_bus);
-		pci_bus_add_devices(pci_bus);
-	}
-}
-
-static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn);
+static int rpaphp_pci_config_bridge(struct pci_dev *dev);
 
 /*****************************************************************************
- rpaphp_pci_config_dn() will recursively configure all devices under the 
- given slot->dn and return the dn's pci_dev.
+ rpaphp_pci_config_slot() will  configure all devices under the 
+ given slot->dn and return the the first pci_dev.
  *****************************************************************************/
 static struct pci_dev *
-rpaphp_pci_config_dn(struct device_node *dn, struct pci_bus *bus)
+rpaphp_pci_config_slot(struct device_node *dn, struct pci_bus *bus)
 {
-	struct device_node *local;
+	struct device_node *eads_first_child = dn->child;
 	struct pci_dev *dev;
+	int num;
+	
+	dbg("Enter %s: dn=%s bus=%s\n", __FUNCTION__, dn->full_name, bus->name);
 
-	for (local = dn->child; local; local = local->sibling) {
-		rpaphp_pci_config_device(bus, local);
-		dev = rpaphp_find_pci_dev(local);
-		if (!rpaphp_pci_config_bridge(dev, local))
+	if (eads_first_child) {
+		/* pci_scan_slot should find all children of EADs */
+		num = pci_scan_slot(bus, PCI_DEVFN(PCI_SLOT(eads_first_child->devfn), 0));
+		if (num) {
+			rpaphp_fixup_new_pci_devices(bus, 1); 
+			pci_bus_add_devices(bus);
+		}
+		dev = rpaphp_find_pci_dev(eads_first_child);
+		if (!dev) {
+			err("No new device found\n");
 			return NULL;
+		}
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 
+			rpaphp_pci_config_bridge(dev);
 	}
-
 	return dev;
 }
 
-static int rpaphp_pci_config_bridge(struct pci_dev *dev, struct device_node *dn)
+static int rpaphp_pci_config_bridge(struct pci_dev *dev)
 {
-	if (dev && dn->child) {	/* dn is a PCI bridge node */
-		struct pci_bus *child;
-		u8 sec_busno;
-
-		/* get busno of downstream bus */
-		pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
-
-		/* add to children of PCI bridge dev->bus */
-		child = pci_add_new_bus(dev->bus, dev, sec_busno);
-		if (!child) {
-			err("%s: could not add second bus\n", __FUNCTION__);
-			return 0;
-		}
-		sprintf(child->name, "PCI Bus #%02x", child->number);
-		/* Fixup subordinate bridge bases and resureces */
-		pcibios_fixup_bus(child);
+	u8 sec_busno;
+	struct pci_bus *child_bus;
+	struct pci_dev *child_dev;
+
+	dbg("Enter %s:  BRIDGE dev=%s\n", __FUNCTION__, pci_name(dev));
 
-		/* may need do more stuff here */
-		rpaphp_pci_config_dn(dn, dev->subordinate);
+	/* get busno of downstream bus */
+	pci_read_config_byte(dev, PCI_SECONDARY_BUS, &sec_busno);
+		
+	/* add to children of PCI bridge dev->bus */
+	child_bus = pci_add_new_bus(dev->bus, dev, sec_busno);
+	if (!child_bus) {
+		err("%s: could not add second bus\n", __FUNCTION__);
+		return -EIO;
 	}
-	return 1;
+	sprintf(child_bus->name, "PCI Bus #%02x", child_bus->number);
+	/* do pci_scan_child_bus */
+	pci_scan_child_bus(child_bus);
+
+	list_for_each_entry(child_dev, &child_bus->devices, bus_list) {
+		eeh_add_device_late(child_dev);
+	}
+
+	 /* fixup new pci devices without touching bus struct */
+	rpaphp_fixup_new_pci_devices(child_bus, 0);
+
+	/* Make the discovered devices available */
+	pci_bus_add_devices(child_bus);
+	return 0;
+}
+
+static void enable_eeh(struct device_node *dn)
+{
+	struct device_node *sib;
+
+	for (sib = dn->child; sib; sib = sib->sibling) 
+		enable_eeh(sib);
+	eeh_add_device_early(dn);
+	return;
+	
+}
+
+#ifdef DEBUG
+static void print_slot_pci_funcs(struct slot *slot)
+{
+	struct list_head *l;
+
+	if (slot->dev_type == PCI_DEV) {
+		printk("pci_funcs of slot[%s]\n", slot->name);
+		if (list_empty(&slot->dev.pci_funcs))
+			printk("	pci_funcs is EMPTY\n");
+
+		list_for_each (l, &slot->dev.pci_funcs) {
+			struct rpaphp_pci_func *func =
+				list_entry(l, struct rpaphp_pci_func, sibling);
+			printk("	FOUND dev=%s\n", pci_name(func->pci_dev));
+		}
+	}
+	return;
+}
+#else
+static void print_slot_pci_funcs(struct slot *slot)
+{
+	return;
+}
+#endif
+
+static int init_slot_pci_funcs(struct slot *slot)
+{
+	struct device_node *child;
+
+	for (child = slot->dn->child; child != NULL; child = child->sibling) {
+		struct pci_dev *pdev = rpaphp_find_pci_dev(child);
+
+		if (pdev) {
+			struct rpaphp_pci_func *func;
+			func = kmalloc(sizeof(struct rpaphp_pci_func), GFP_KERNEL);
+			if (!func) 
+				return -ENOMEM;
+			memset(func, 0, sizeof(struct rpaphp_pci_func));
+			INIT_LIST_HEAD(&func->sibling);
+			func->pci_dev = pdev;
+			list_add_tail(&func->sibling, &slot->dev.pci_funcs);
+			print_slot_pci_funcs(slot);
+		} else {
+			err("%s: dn=%s has no pci_dev\n", 
+				__FUNCTION__, child->full_name);
+			return -EIO;
+		}
+	}
+	return 0;
 }
 
-static struct pci_dev *rpaphp_config_pci_adapter(struct slot *slot)
+static int rpaphp_config_pci_adapter(struct slot *slot)
 {
 	struct pci_bus *pci_bus;
-	struct pci_dev *dev = NULL;
+	struct pci_dev *dev;
+	int rc = -ENODEV;
 
 	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
 
@@ -256,38 +318,74 @@
 			err("%s: can't find bus structure\n", __FUNCTION__);
 			goto exit;
 		}
-
-		eeh_add_device_early(slot->dn->child);
-		dev = rpaphp_pci_config_dn(slot->dn, pci_bus);
-		eeh_add_device_late(dev);
+		enable_eeh(slot->dn);
+		dev = rpaphp_pci_config_slot(slot->dn, pci_bus);
+		if (!dev) {
+			err("%s: can't find any devices.\n", __FUNCTION__);
+			goto exit;
+		}
+		/* associate corresponding pci_dev */	
+		rc = init_slot_pci_funcs(slot);
+		if (rc)
+			goto exit;
+		print_slot_pci_funcs(slot);
+		if (!list_empty(&slot->dev.pci_funcs)) 
+			rc = 0;
 	} else {
 		/* slot is not enabled */
 		err("slot doesn't have pci_dev structure\n");
-		dev = NULL;
 	}
-
 exit:
-	dbg("Exit %s: pci_dev %s\n", __FUNCTION__, dev ? "found" : "not found");
-	return dev;
+	dbg("Exit %s:  rc=%d\n", __FUNCTION__, rc);
+	return rc;
+}
+
+
+static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
+{
+	eeh_remove_device(dev);
+	if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		struct pci_bus *bus = dev->subordinate;
+		struct list_head *ln;
+		if (!bus)
+			return; 
+		for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+			struct pci_dev *pdev = pci_dev_b(ln);
+			if (pdev)
+				rpaphp_eeh_remove_bus_device(pdev);
+		}
+
+	}
+	return;
 }
 
 int rpaphp_unconfig_pci_adapter(struct slot *slot)
 {
 	int retval = 0;
+	struct list_head *ln;
 
 	dbg("Entry %s: slot[%s]\n", __FUNCTION__, slot->name);
-	if (!slot->dev.pci_dev) {
-		info("%s: no card in slot[%s]\n", __FUNCTION__, slot->name);
+	if (list_empty(&slot->dev.pci_funcs)) {
+		err("%s: slot[%s] doesn't have any devices.\n", __FUNCTION__, 
+			slot->name);
 
 		retval = -EINVAL;
 		goto exit;
 	}
-	/* remove the device from the pci core */
-	eeh_remove_device(slot->dev.pci_dev);
-	pci_remove_bus_device(slot->dev.pci_dev);
-
+	/* remove the devices from the pci core */
+	list_for_each (ln, &slot->dev.pci_funcs) {
+		struct rpaphp_pci_func *func;
+	
+		func = list_entry(ln, struct rpaphp_pci_func, sibling);
+		if (func->pci_dev) {
+			rpaphp_eeh_remove_bus_device(func->pci_dev);
+			pci_remove_bus_device(func->pci_dev); 
+		}
+		kfree(func);
+	}
+	INIT_LIST_HEAD(&slot->dev.pci_funcs);
 	slot->state = NOT_CONFIGURED;
-	info("%s: adapter in slot[%s] unconfigured.\n", __FUNCTION__,
+	info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
 	     slot->name);
 exit:
 	dbg("Exit %s, rc=0x%x\n", __FUNCTION__, retval);
@@ -303,7 +401,7 @@
 				      &slot->hotplug_slot->info->
 				      adapter_status);
 	if (slot->hotplug_slot->info->adapter_status == NOT_VALID) {
-		dbg("%s: NOT_VALID: skip dn->full_name=%s\n",
+		err("%s: NOT_VALID: skip dn->full_name=%s\n",
 		    __FUNCTION__, slot->dn->full_name);
 		return -1;
 	}
@@ -314,35 +412,41 @@
 {
 	slot->bridge = rpaphp_find_bridge_pdev(slot);
 	if (!slot->bridge) {	/* slot being added doesn't have pci_dev yet */
-		dbg("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name);
-		dealloc_slot_struct(slot);
-		return 1;
+		err("%s: no pci_dev for bridge dn %s\n", __FUNCTION__, slot->name);
+		goto exit_rc;
 	}
-	
+	dbg("%s set slot->name to %s\n",  __FUNCTION__, pci_name(slot->bridge));
 	strcpy(slot->name, pci_name(slot->bridge));
+
 	/* find slot's pci_dev if it's not empty */
 	if (slot->hotplug_slot->info->adapter_status == EMPTY) {
 		slot->state = EMPTY;	/* slot is empty */
-		slot->dev.pci_dev = NULL;
 	} else {
 		/* slot is occupied */
 		if (!(slot->dn->child)) {
 			/* non-empty slot has to have child */
-			err("%s: slot[%s]'s device_node doesn't have child for adapter\n", __FUNCTION__, slot->name);
-			dealloc_slot_struct(slot);
-			return 1;
+			err("%s: slot[%s]'s device_node doesn't have child for adapter\n", 
+				__FUNCTION__, slot->name);
+			goto exit_rc;
+		}
+		if (init_slot_pci_funcs(slot)) {
+			err("%s: init_slot_pci_funcs failed\n", __FUNCTION__);
+			goto exit_rc;
 		}
-		slot->dev.pci_dev = rpaphp_find_adapter_pdev(slot);
-		if (slot->dev.pci_dev) {
+		print_slot_pci_funcs(slot);
+		if (!list_empty(&slot->dev.pci_funcs)) {
 			slot->state = CONFIGURED;
-		
+	
 		} else {
 			/* DLPAR add as opposed to 
-			 * boot time */
+		 	 * boot time */
 			slot->state = NOT_CONFIGURED;
 		}
 	}
 	return 0;
+exit_rc:
+	dealloc_slot_struct(slot);
+	return 1;
 }
 
 int register_pci_slot(struct slot *slot)
@@ -350,14 +454,17 @@
 	int rc = 1;
 
 	slot->dev_type = PCI_DEV;
+	if (slot->type == EMBEDDED)
+		slot->removable = EMBEDDED;
+	else
+		slot->removable = HOTPLUG;
+	INIT_LIST_HEAD(&slot->dev.pci_funcs);
 	if (setup_pci_hotplug_slot_info(slot))
 		goto exit_rc;
 	if (setup_pci_slot(slot))
 		goto exit_rc;
 	rc = register_slot(slot);
 exit_rc:
-	if (rc)
-		dealloc_slot_struct(slot);
 	return rc;
 }
 
@@ -371,12 +478,12 @@
 	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->name);
-		if ((slot->dev.pci_dev =
-		     rpaphp_config_pci_adapter(slot)) != NULL) {
+		dbg("%s : slot[%s] is occupied.\n", __FUNCTION__, slot->name);
+		retval = rpaphp_config_pci_adapter(slot);
+		if (!retval) {
 			slot->state = CONFIGURED;
-			dbg("%s: PCI adapter %s in slot[%s] has been configured\n", 
-				__FUNCTION__, pci_name(slot->dev.pci_dev), slot->name);
+			dbg("%s: PCI devices in slot[%s] has been configured\n", 
+				__FUNCTION__, slot->name);
 		} else {
 			slot->state = NOT_CONFIGURED;
 			dbg("%s: no pci_dev struct for adapter in slot[%s]\n",
@@ -392,10 +499,31 @@
 		retval = -EINVAL;
 	}
 exit:
-	if (slot->state != NOT_VALID)
-		rpaphp_set_attention_status(slot, LED_ON);
-	else
-		rpaphp_set_attention_status(slot, LED_ID);
 	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
 	return retval;
 }
+
+struct hotplug_slot *rpaphp_find_hotplug_slot(struct pci_dev *dev)
+{
+	struct list_head	*tmp, *n;
+	struct slot		*slot;
+
+	list_for_each_safe(tmp, n, &rpaphp_slot_head) {
+		struct pci_bus *bus;
+		struct list_head *ln;
+
+		slot = list_entry(tmp, struct slot, rpaphp_slot_list);
+		bus = slot->bridge->subordinate;
+		if (!bus)
+			return NULL; /* shouldn't be here */
+		for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+                                struct pci_dev *pdev = pci_dev_b(ln);
+				if (pdev == dev)
+					return slot->hotplug_slot;
+		}
+	}
+
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(rpaphp_find_hotplug_slot);
diff -Nru a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
--- a/drivers/pci/hotplug/rpaphp_slot.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/rpaphp_slot.c	2004-06-14 00:00:16 -07:00
@@ -29,6 +29,35 @@
 #include <linux/pci.h>
 #include "rpaphp.h"
 
+static ssize_t removable_read_file (struct hotplug_slot *php_slot, char *buf)
+{
+	u8 value;
+	int retval = -ENOENT;
+	struct slot *slot = (struct slot *)php_slot->private;
+
+	if (!slot)
+		return retval;
+
+	value = slot->removable;
+	retval = sprintf (buf, "%d\n", value);
+	return retval;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_removable = {
+	.attr = {.name = "phy_removable", .mode = S_IFREG | S_IRUGO},
+	.show = removable_read_file,
+};
+
+static void rpaphp_sysfs_add_attr_removable (struct hotplug_slot *slot)
+{
+	sysfs_create_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
+}
+
+static void rpaphp_sysfs_remove_attr_removable (struct hotplug_slot *slot)
+{
+	sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_removable.attr);
+}
+
 static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
 {
         char *value;
@@ -53,7 +82,7 @@
 	sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr);
 }
 
-void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
+static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
 {
 	sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr);
 }
@@ -68,6 +97,17 @@
 
 void dealloc_slot_struct(struct slot *slot)
 {
+	struct list_head *ln, *n;
+
+	if (slot->dev_type == PCI_DEV) {
+		list_for_each_safe (ln, n, &slot->dev.pci_funcs) {
+			struct rpaphp_pci_func *func;
+
+			func = list_entry(ln, struct rpaphp_pci_func, sibling);
+			kfree(func);
+		}
+	}
+
 	kfree(slot->hotplug_slot->info);
 	kfree(slot->hotplug_slot->name);
 	kfree(slot->hotplug_slot);
@@ -86,7 +126,7 @@
 	memset(slot, 0, sizeof (struct slot));
 	slot->hotplug_slot = kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
 	if (!slot->hotplug_slot)
-		goto error_slot;
+		goto error_slot;	
 	memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
 	slot->hotplug_slot->info = kmalloc(sizeof (struct hotplug_slot_info),
 					   GFP_KERNEL);
@@ -95,7 +135,7 @@
 	memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
 	slot->hotplug_slot->name = kmalloc(BUS_ID_SIZE + 1, GFP_KERNEL);
 	if (!slot->hotplug_slot->name)
-		goto error_info;
+		goto error_info;	
 	slot->location = kmalloc(strlen(drc_name) + 1, GFP_KERNEL);
 	if (!slot->location)
 		goto error_name;
@@ -107,9 +147,8 @@
 	slot->hotplug_slot->private = slot;
 	slot->hotplug_slot->ops = &rpaphp_hotplug_slot_ops;
 	slot->hotplug_slot->release = &rpaphp_release_slot;
-	slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
-
-	return slot;
+	
+	return (slot);
 
 error_name:
 	kfree(slot->hotplug_slot->name);
@@ -123,15 +162,56 @@
 	return NULL;
 }
 
+static int is_registered(struct slot *slot)
+{
+	struct slot             *tmp_slot;
+
+	list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
+		if (!strcmp(tmp_slot->name, slot->name))
+			return 1;
+	}	
+	return 0;
+}
+
+int deregister_slot(struct slot *slot)
+{
+	int retval = 0;
+	struct hotplug_slot *php_slot = slot->hotplug_slot;
+
+	 dbg("%s - Entry: deregistering slot=%s\n",
+		__FUNCTION__, slot->name);
+
+	list_del(&slot->rpaphp_slot_list);
+	
+	/* remove "phy_location" file */
+	rpaphp_sysfs_remove_attr_location(php_slot);
+
+	/* remove "phy_removable" file */
+	rpaphp_sysfs_remove_attr_removable(php_slot);
+
+	retval = pci_hp_deregister(php_slot);
+	if (retval)
+		err("Problem unregistering a slot %s\n", slot->name);
+	else
+		num_slots--;
+
+	dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+	return retval;
+}
+
 int register_slot(struct slot *slot)
 {
 	int retval;
-	char *vio_uni_addr = NULL;
 
-	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
-		__FUNCTION__, slot->dn->full_name, slot->index, slot->name,
+	dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n", 
+		__FUNCTION__, slot->dn->full_name, slot->index, slot->name, 
 		slot->power_domain, slot->type);
-
+	/* should not try to register the same slot twice */
+	if (is_registered(slot)) { /* should't be here */
+		err("register_slot: slot[%s] is already registered\n", slot->name);
+		rpaphp_release_slot(slot->hotplug_slot);
+		return 1;
+	}	
 	retval = pci_hp_register(slot->hotplug_slot);
 	if (retval) {
 		err("pci_hp_register failed with error %d\n", retval);
@@ -142,30 +222,40 @@
 	/* create "phy_locatoin" file */
 	rpaphp_sysfs_add_attr_location(slot->hotplug_slot);	
 
+	/* create "phy_removable" file */
+	rpaphp_sysfs_add_attr_removable(slot->hotplug_slot);	
+
 	/* add slot to our internal list */
 	dbg("%s adding slot[%s] to rpaphp_slot_list\n",
 	    __FUNCTION__, slot->name);
 
 	list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
 
-	if (vio_uni_addr)
-		info("Slot [%s](vio_uni_addr=%s) registered\n",
-		     slot->name, vio_uni_addr);
+	if (slot->dev_type == VIO_DEV)
+		info("Slot [%s](VIO location=%s) registered\n",
+		     slot->name, slot->location);
 	else
-		info("Slot [%s](bus_id=%s) registered\n",
-		     slot->name, pci_name(slot->bridge));
+		info("Slot [%s](PCI location=%s) registered\n",
+		     slot->name, slot->location);
 	num_slots++;
 	return 0;
 }
 
 int rpaphp_get_power_status(struct slot *slot, u8 * value)
 {
-	int rc;
-
-	rc = rtas_get_power_level(slot->power_domain, (int *) value);
-	if (rc)
-		err("failed to get power-level for slot(%s), rc=0x%x\n",
-		    slot->name, rc);
+	int rc = 0;
+	
+	if (slot->type == EMBEDDED) {
+		dbg("%s set to POWER_ON for EMBEDDED slot %s\n",
+			__FUNCTION__, slot->location);
+		*value = POWER_ON;
+	}
+	else {
+		rc = rtas_get_power_level(slot->power_domain, (int *) value);
+		if (rc)
+			err("failed to get power-level for slot(%s), rc=0x%x\n",
+		    		slot->location, rc);
+	}
 
 	return rc;
 }
@@ -177,8 +267,8 @@
 	/* status: LED_OFF or LED_ON */
 	rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
 	if (rc)
-		err("slot(%s) set attention-status(%d) failed! rc=0x%x\n",
-		    slot->name, status, rc);
+		err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
+		    slot->name, slot->location, slot->index, status, rc);
 
 	return rc;
 }
diff -Nru a/drivers/pci/hotplug/rpaphp_vio.c b/drivers/pci/hotplug/rpaphp_vio.c
--- a/drivers/pci/hotplug/rpaphp_vio.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/rpaphp_vio.c	2004-06-14 00:00:16 -07:00
@@ -74,11 +74,11 @@
 	int rc = 1;
 	struct slot *slot = NULL;
 	
+	name = rpaphp_get_drc_name(dn);
+	if (!name)
+		goto exit_rc;
 	index = (u32 *) get_property(dn, "ibm,my-drc-index", NULL);
 	if (!index)
-		goto exit_rc;
-	name = get_property(dn, "ibm,loc-code", NULL);
-	if (!name)
 		goto exit_rc;
 	if (!(slot = alloc_slot_struct(dn, *index, name, 0))) {
 		rc = -ENOMEM;
diff -Nru a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
--- a/drivers/pci/hotplug/shpchp.h	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/shpchp.h	2004-06-14 00:00:16 -07:00
@@ -61,6 +61,7 @@
 	u8 configured;
 	u8 switch_save;
 	u8 presence_save;
+	u8 pwr_save;
 	u32 base_length[0x06];
 	u8 base_type[0x06];
 	u16 reserved2;
diff -Nru a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
--- a/drivers/pci/hotplug/shpchp_ctrl.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/shpchp_ctrl.c	2004-06-14 00:00:16 -07:00
@@ -137,6 +137,8 @@
 	p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
+	dbg("%s: Card present %x Power status %x\n", __FUNCTION__,
+		func->presence_save, func->pwr_save);
 
 	if (getstatus) {
 		/*
@@ -145,6 +147,10 @@
 		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
 		func->switch_save = 0;
 		taskInfo->event_type = INT_SWITCH_OPEN;
+		if (func->pwr_save && func->presence_save) {
+			taskInfo->event_type = INT_POWER_FAULT;
+			err("Surprise Removal of card\n");
+		}
 	} else {
 		/*
 		 *  Switch closed
@@ -1427,6 +1433,7 @@
 					rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, adapter_speed);
 					if (rc) {
 						err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
+						up(&ctrl->crit_sect);
 						return WRONG_BUS_FREQUENCY;
 					}
 				
@@ -1438,6 +1445,7 @@
 						err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n",
 								  __FUNCTION__);
 						err("%s: Error code (%d)\n", __FUNCTION__, rc);
+						up(&ctrl->crit_sect);
 						return WRONG_BUS_FREQUENCY;
 					}
 					/* Done with exclusive hardware access */
@@ -1589,8 +1597,9 @@
 		func->status = 0;
 		func->switch_save = 0x10;
 		func->is_a_board = 0x01;
+		func->pwr_save = 1;
 
-		/* next, we will instantiate the linux pci_dev structures 
+		/* Next, we will instantiate the linux pci_dev structures 
 		 * (with appropriate driver notification, if already present) 
 		 */
 		index = 0;
@@ -1781,6 +1790,7 @@
 		func->function = 0;
 		func->configured = 0;
 		func->switch_save = 0x10;
+		func->pwr_save = 0;
 		func->is_a_board = 0;
 	}
 
@@ -1807,7 +1817,6 @@
 {
 	struct slot *p_slot = (struct slot *) slot;
 	u8 getstatus;
-	int rc;
 	
 	pushbutton_pending = 0;
 
@@ -1821,23 +1830,7 @@
 		p_slot->state = POWEROFF_STATE;
 		dbg("In power_down_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device);
 
-		if (shpchp_disable_slot(p_slot)) {
-			/* Wait for exclusive access to hardware */
-			down(&p_slot->ctrl->crit_sect);
-
-			/* Turn on the Attention LED */
-			rc = p_slot->hpc_ops->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->ctrl);
-
-			/* Done with exclusive hardware access */
-			up(&p_slot->ctrl->crit_sect);
-		}
+		shpchp_disable_slot(p_slot);
 		p_slot->state = STATIC_STATE;
 	} else {
 		p_slot->state = POWERON_STATE;
@@ -1847,15 +1840,6 @@
 			/* Wait for exclusive access to hardware */
 			down(&p_slot->ctrl->crit_sect);
 
-			/* Turn off the green LED */
-			rc = p_slot->hpc_ops->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->ctrl);
-			
 			p_slot->hpc_ops->green_led_off(p_slot);
 
 			/* Wait for the command to complete */
@@ -2096,7 +2080,7 @@
 	func = shpchp_slot_find(p_slot->bus, p_slot->device, 0);
 	if (!func) {
 		dbg("%s: Error! slot NULL\n", __FUNCTION__);
-		return (1);
+		return 1;
 	}
 
 	/* Check to see if (latch closed, card present, power off) */
@@ -2105,19 +2089,19 @@
 	if (rc || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (rc || getstatus) {
 		info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
@@ -2125,7 +2109,7 @@
 
 	func = shpchp_slot_create(p_slot->bus);
 	if (func == NULL)
-		return (1);
+		return 1;
 
 	func->bus = p_slot->bus;
 	func->device = p_slot->device;
@@ -2135,6 +2119,8 @@
 
 	/* We have to save the presence info for these slots */
 	p_slot->hpc_ops->get_adapter_status(p_slot, &(func->presence_save));
+	p_slot->hpc_ops->get_power_status(p_slot, &(func->pwr_save));
+	dbg("%s: func->pwr_save %x\n", __FUNCTION__, func->pwr_save);
 	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	func->switch_save = !getstatus? 0x10:0;
 
@@ -2181,7 +2167,7 @@
 	struct pci_func *func;
 
 	if (!p_slot->ctrl)
-		return (1);
+		return 1;
 
 	/* Check to see if (latch closed, card present, power on) */
 	down(&p_slot->ctrl->crit_sect);
@@ -2190,19 +2176,19 @@
 	if (ret || !getstatus) {
 		info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 	if (ret || getstatus) {
 		info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 	if (ret || !getstatus) {
 		info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
 		up(&p_slot->ctrl->crit_sect);
-		return (0);
+		return 1;
 	}
 	up(&p_slot->ctrl->crit_sect);
 
diff -Nru a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
--- a/drivers/pci/hotplug/shpchp_pci.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/shpchp_pci.c	2004-06-14 00:00:16 -07:00
@@ -263,6 +263,7 @@
 				new_slot->function = (u8) function;
 				new_slot->is_a_board = 1;
 				new_slot->switch_save = 0x10;
+				new_slot->pwr_save = 1;
 				/* In case of unsupported board */
 				new_slot->status = DevError;
 				new_slot->pci_dev = pci_find_slot(new_slot->bus,
diff -Nru a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c
--- a/drivers/pci/hotplug/shpchprm_acpi.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/shpchprm_acpi.c	2004-06-14 00:00:16 -07:00
@@ -218,6 +218,10 @@
 	}
 
 	ab->_hpp = kmalloc (sizeof (struct acpi__hpp), GFP_KERNEL);
+	if (!ab->_hpp) {
+		err ("acpi_shpchprm:%s alloc for _HPP failed\n", path_name);
+		goto free_and_return;
+	}
 	memset(ab->_hpp, 0, sizeof(struct acpi__hpp));
 
 	ab->_hpp->cache_line_size	= nui[0];
@@ -1391,7 +1395,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->bus;
 	int devn, funn;
 	u32	vid;
@@ -1406,11 +1410,19 @@
 
 			if (vid != 0xFFFFFFFF) {
 				func = shpchp_slot_find(busn, devn, funn);
-				if (!func)
-					continue;
-				configure_existing_function(ctrl, func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					shpchprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					shpchprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				shpchprm_dump_func_res(func);
 			}
 		}
 	}
diff -Nru a/drivers/pci/hotplug/shpchprm_nonacpi.c b/drivers/pci/hotplug/shpchprm_nonacpi.c
--- a/drivers/pci/hotplug/shpchprm_nonacpi.c	2004-06-14 00:00:16 -07:00
+++ b/drivers/pci/hotplug/shpchprm_nonacpi.c	2004-06-14 00:00:16 -07:00
@@ -208,7 +208,7 @@
 
 static int bind_pci_resources_to_slots ( struct controller *ctrl)
 {
-	struct pci_func *func;
+	struct pci_func *func, new_func;
 	int busn = ctrl->slot_bus;
 	int devn, funn;
 	u32	vid;
@@ -226,11 +226,19 @@
 
 			if (vid != 0xFFFFFFFF) {
 				func = shpchp_slot_find(busn, devn, funn);
-				if (!func)
-					continue;
-				configure_existing_function(ctrl, func);
+				if (!func) {
+					memset(&new_func, 0, sizeof(struct pci_func));
+					new_func.bus = busn;
+					new_func.device = devn;
+					new_func.function = funn;
+					new_func.is_a_board = 1;
+					configure_existing_function(ctrl, &new_func);
+					phprm_dump_func_res(&new_func);
+				} else {
+					configure_existing_function(ctrl, func);
+					phprm_dump_func_res(func);
+				}
 				dbg("aCCF:existing PCI 0x%x Func ResourceDump\n", ctrl->bus);
-				phprm_dump_func_res(func);
 			}
 		}
 	}