patch-2.4.20 linux-2.4.20/drivers/hotplug/ibmphp_core.c

Next file: linux-2.4.20/drivers/hotplug/ibmphp_ebda.c
Previous file: linux-2.4.20/drivers/hotplug/ibmphp.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/hotplug/ibmphp_core.c linux-2.4.20/drivers/hotplug/ibmphp_core.c
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.1"
+#define DRIVER_VERSION	"0.6"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
@@ -88,6 +88,8 @@
 	slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus);
 	if (READ_BUS_MODE (slot_cur->ctrl))
 		slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus);
+	else
+		slot_cur->bus_on->current_bus_mode = 0xFF;
 
 	debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode);
 	
@@ -106,13 +108,17 @@
 	return rc;
 }
 
-static int get_max_slots (void)
+static int __init get_max_slots (void)
 {
+	struct slot * slot_cur;
 	struct list_head * tmp;
-	int slot_count = 0;
+	u8 slot_count = 0;
 
-	list_for_each (tmp, &ibmphp_slot_head) 
-		++slot_count;
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
+		/* sometimes the hot-pluggable slots start with 4 (not always from 1 */
+		slot_count = max (slot_count, slot_cur->number);
+	}
 	return slot_count;
 }
 
@@ -330,7 +336,7 @@
 			memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot));
 			hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status));
 			if (!hpcrc) {
-				*value = SLOT_POWER (myslot.status);
+				*value = SLOT_PWRGD (myslot.status);
 				rc = 0;
 			}
 		}
@@ -378,14 +384,15 @@
 	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
-/*
-static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -393,32 +400,40 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			mode = pslot->bus_on->supported_bus_mode;
-			*value = pslot->bus_on->supported_speed;
-			*value &= 0x0f;
-
-			if (mode == BUS_MODE_PCIX)
-				*value |= 0x80;
-			else if (mode == BUS_MODE_PCI)
-				*value |= 0x40;
-			else
-				*value |= 0x20;
+			mode = pslot->supported_bus_mode;
+			*value = pslot->supported_speed; 
+			switch (*value) {
+			case BUS_SPEED_33:
+				break;
+			case BUS_SPEED_66:
+				if (mode == BUS_MODE_PCIX) 
+					*value += 0x01;
+				break;
+			case BUS_SPEED_100:
+			case BUS_SPEED_133:
+				*value = pslot->supported_speed + 0x01;
+				break;
+			default:
+				/* Note (will need to change): there would be soon 256, 512 also */
+				rc = -ENODEV;
+			}
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
 
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -429,24 +444,35 @@
 			if (!rc) {
 				mode = pslot->bus_on->current_bus_mode;
 				*value = pslot->bus_on->current_speed;
-				*value &= 0x0f;
-				
-				if (mode == BUS_MODE_PCIX)
-					*value |= 0x80;
-				else if (mode == BUS_MODE_PCI)
-					*value |= 0x40;
-				else
-					*value |= 0x20;	
+				switch (*value) {
+				case BUS_SPEED_33:
+					break;
+				case BUS_SPEED_66:
+					if (mode == BUS_MODE_PCIX) 
+						*value += 0x01;
+					else if (mode == BUS_MODE_PCI)
+						;
+					else
+						*value = PCI_SPEED_UNKNOWN;
+					break;
+				case BUS_SPEED_100:
+				case BUS_SPEED_133:
+					*value += 0x01;
+					break;
+				default:
+					/* Note of change: there would also be 256, 512 soon */
+					rc = -ENODEV;
+				}
 			}
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
-
+/*
 static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
 {
 	int rc = -ENODEV;
@@ -454,7 +480,7 @@
 	int hpcrc = 0;
 	struct slot myslot;
 
-	debug ("get_max_adapter_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
 
 	if (flag)
 		ibmphp_lock_operations ();
@@ -485,17 +511,16 @@
 	if (flag)
 		ibmphp_unlock_operations ();
 
-	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
+	debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
 
-static int get_card_bus_names (struct hotplug_slot *hotplug_slot, char * value)
+static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot = NULL;
-	struct pci_dev * dev = NULL;
 
-	debug ("get_card_bus_names - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
+	debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot);
 
 	ibmphp_lock_operations ();
 
@@ -503,40 +528,33 @@
 		pslot = (struct slot *) hotplug_slot->private;
 		if (pslot) {
 			rc = 0;
-			if (pslot->func)
-				dev = pslot->func->dev;
-			else
-                		dev = pci_find_slot (pslot->bus, (pslot->device << 3) | (0x00 & 0x7));
-			if (dev) 
-				snprintf (value, 100, "Bus %d : %s", pslot->bus,dev->name);
-			else
-				snprintf (value, 100, "Bus %d", pslot->bus);
-			
-				
+			snprintf (value, 100, "Bus %x", pslot->bus);
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_card_bus_names - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value);
 	return rc;
 }
-
 */
+
 /*******************************************************************************
  * This routine will initialize the ops data structure used in the validate
  * function. It will also power off empty slots that are powered on since BIOS
  * leaves those on, albeit disconnected
  ******************************************************************************/
-static int init_ops (void)
+static int __init init_ops (void)
 {
 	struct slot *slot_cur;
+	struct list_head *tmp;
 	int retval;
-	int j;
 	int rc;
+	int j;
 
 	for (j = 0; j < MAX_OPS; j++) {
 		ops[j] = (int *) kmalloc ((max_slots + 1) * sizeof (int), GFP_KERNEL);
+		memset (ops[j], 0, (max_slots + 1) * sizeof (int));
 		if (!ops[j]) {
 			err ("out of system memory \n");
 			return -ENOMEM;
@@ -547,12 +565,13 @@
 	ops[REMOVE][0] = 0;
 	ops[DETAIL][0] = 0;
 
-	for (j = 1; j <= max_slots; j++) {
+	list_for_each (tmp, &ibmphp_slot_head) {
+		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
 
-		slot_cur = ibmphp_get_slot_from_physical_num (j);
+		if (!slot_cur)
+			return -ENODEV;
 
 		debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number);
-
 		if (slot_cur->ctrl->revision == 0xFF) 
 			if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision))
 				return -1;
@@ -572,21 +591,21 @@
 		debug ("status = %x, ext_status = %x\n", slot_cur->status, slot_cur->ext_status);
 		debug ("SLOT_POWER = %x, SLOT_PRESENT = %x, SLOT_LATCH = %x\n", SLOT_POWER (slot_cur->status), SLOT_PRESENT (slot_cur->status), SLOT_LATCH (slot_cur->status));
 
-		if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+		if (!(SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
 			/* No power, adapter, and latch closed */
-			ops[ADD][j] = 1;
+			ops[ADD][slot_cur->number] = 1;
 		else
-			ops[ADD][j] = 0;
+			ops[ADD][slot_cur->number] = 0;
 
-		ops[DETAIL][j] = 1;
+		ops[DETAIL][slot_cur->number] = 1;
 
-		if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
+		if ((SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status)))
 			/*Power,adapter,latch closed */
-			ops[REMOVE][j] = 1;
+			ops[REMOVE][slot_cur->number] = 1;
 		else
-			ops[REMOVE][j] = 0;
+			ops[REMOVE][slot_cur->number] = 0;
 
-		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
+		if ((SLOT_PWRGD (slot_cur->status)) && !(SLOT_PRESENT (slot_cur->status)) && !(SLOT_LATCH (slot_cur->status))) {
 			debug ("BEFORE POWER OFF COMMAND\n");
 				rc = power_off (slot_cur);
 				if (rc)
@@ -624,7 +643,7 @@
 	if (retval)
 		return retval;
 
-	if (!(SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	if (!(SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
 	    && !(SLOT_LATCH (slot_cur->status)))
 		ops[ADD][number] = 1;
 	else
@@ -632,7 +651,7 @@
 
 	ops[DETAIL][number] = 1;
 
-	if ((SLOT_POWER (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
+	if ((SLOT_PWRGD (slot_cur->status)) && (SLOT_PRESENT (slot_cur->status))
 	    && !(SLOT_LATCH (slot_cur->status)))
 		ops[REMOVE][number] = 1;
 	else
@@ -667,9 +686,10 @@
 int ibmphp_update_slot_info (struct slot *slot_cur)
 {
 	struct hotplug_slot_info *info;
-	char buffer[10];
+	char buffer[30];
 	int rc;
-//	u8 bus_speed;
+	u8 bus_speed;
+	u8 mode;
 
 	info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
 	if (!info) {
@@ -677,8 +697,8 @@
 		return -ENOMEM;
 	}
         
-	snprintf (buffer, 10, "%d", slot_cur->number);
-	info->power_status = SLOT_POWER (slot_cur->status);
+	strncpy (buffer, slot_cur->hotplug_slot->name, 30);
+	info->power_status = SLOT_PWRGD (slot_cur->status);
 	info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status);
 	info->latch_status = SLOT_LATCH (slot_cur->status);
         if (!SLOT_PRESENT (slot_cur->status)) {
@@ -688,21 +708,33 @@
                 info->adapter_status = 1;
 //		get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0);
 	}
-/*
+
 	bus_speed = slot_cur->bus_on->current_speed;
-	bus_speed &= 0x0f;
-                        
-	if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
-		bus_speed |= 0x80;
-	else if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCI)
-		bus_speed |= 0x40;
-	else
-		bus_speed |= 0x20;
+	mode = slot_cur->bus_on->current_bus_mode;
 
-	info->cur_bus_speed_status = bus_speed;
-	info->max_bus_speed_status = slot_cur->hotplug_slot->info->max_bus_speed_status;
-	// To do: card_bus_names 
-*/	
+	switch (bus_speed) {
+	case BUS_SPEED_33:
+		break;
+	case BUS_SPEED_66:
+		if (mode == BUS_MODE_PCIX) 
+			bus_speed += 0x01;
+		else if (mode == BUS_MODE_PCI)
+			;
+		else
+			bus_speed = PCI_SPEED_UNKNOWN;
+		break;
+	case BUS_SPEED_100:
+	case BUS_SPEED_133:
+		bus_speed += 0x01;
+		break;
+	default:
+		bus_speed = PCI_SPEED_UNKNOWN;
+	}
+
+	info->cur_bus_speed = bus_speed;
+	info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed;
+	// To do: bus_names 
+	
 	rc = pci_hp_change_slot_info (buffer, info);
 	kfree (info);
 	return rc;
@@ -775,8 +807,10 @@
 	struct list_head * tmp;
 	struct list_head * next;
 
-	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+	debug ("%s -- enter\n", __FUNCTION__);
 
+	list_for_each_safe (tmp, next, &ibmphp_slot_head) {
+	
 		slot_cur = list_entry (tmp, struct slot, ibm_slot_list);
 
 		pci_hp_deregister (slot_cur->hotplug_slot);
@@ -795,7 +829,9 @@
 		ibmphp_unconfigure_card (&slot_cur, -1);  /* we don't want to actually remove the resources, since free_resources will do just that */
 
 		kfree (slot_cur);
+		slot_cur = NULL;
 	}
+	debug ("%s -- exit\n", __FUNCTION__);
 }
 
 static int ibm_is_pci_dev_in_use (struct pci_dev *dev)
@@ -851,7 +887,7 @@
 	if (temp_func)
 		temp_func->dev = NULL;
 	else
-		err ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
+		debug ("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);
 
 	return 0;
 }
@@ -893,12 +929,12 @@
 }
 
 static struct pci_visit ibm_unconfigure_functions_phase1 = {
-	post_visit_pci_dev:	ibm_unconfigure_visit_pci_dev_phase1,
+	.post_visit_pci_dev =	ibm_unconfigure_visit_pci_dev_phase1,
 };
 
 static struct pci_visit ibm_unconfigure_functions_phase2 = {
-	post_visit_pci_bus:	ibm_unconfigure_visit_pci_bus_phase2,
-	post_visit_pci_dev:	ibm_unconfigure_visit_pci_dev_phase2,
+	.post_visit_pci_bus =	ibm_unconfigure_visit_pci_bus_phase2,
+	.post_visit_pci_dev =	ibm_unconfigure_visit_pci_dev_phase2,
 };
 
 static int ibm_unconfigure_device (struct pci_func *func)
@@ -962,9 +998,37 @@
 }
 
 static struct pci_visit configure_functions = {
-	visit_pci_dev:	configure_visit_pci_dev,
+	.visit_pci_dev =configure_visit_pci_dev,
 };
 
+
+/*
+ * The following function is to fix kernel bug regarding 
+ * getting bus entries, here we manually add those primary 
+ * bus entries to kernel bus structure whenever apply
+ */
+
+static u8 bus_structure_fixup (u8 busno)
+{
+	struct pci_bus bus_t;
+	struct pci_dev dev_t;
+	u16 l;
+
+	if (find_bus (busno) || !(ibmphp_find_same_bus_num (busno)))
+		return 1;
+	bus_t.number = busno;
+	bus_t.ops = ibmphp_pci_root_ops;
+	dev_t.bus = &bus_t;
+	for (dev_t.devfn=0; dev_t.devfn<256; dev_t.devfn += 8) {
+		if (!pci_read_config_word (&dev_t, PCI_VENDOR_ID, &l) &&  l != 0x0000 && l != 0xffff) {
+			debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__);
+			pci_scan_bus (busno, ibmphp_pci_root_ops, NULL);
+			break;
+		}
+	}
+	return 0;
+}
+
 static int ibm_configure_device (struct pci_func *func)
 {
 	unsigned char bus;
@@ -972,6 +1036,7 @@
 	struct pci_bus *child;
 	struct pci_dev *temp;
 	int rc = 0;
+	int flag = 0;	/* this is to make sure we don't double scan the bus, for bridged devices primarily */
 
 	struct pci_dev_wrapped wrapped_dev;
 	struct pci_bus_wrapped wrapped_bus;
@@ -980,6 +1045,8 @@
 	memset (&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
 	memset (&dev0, 0, sizeof (struct pci_dev));
 
+	if (!(bus_structure_fixup (func->busno)))
+		flag = 1;
 	if (func->dev == NULL)
 		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
 
@@ -995,7 +1062,7 @@
 			return 0;
 		}
 	}
-	if (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+	if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
 		pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus);
 		child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus);
 		pci_do_scan_bus (child);
@@ -1009,6 +1076,7 @@
 	}
 	return rc;
 }
+
 /*******************************************************
  * Returns whether the bus is empty or not 
  *******************************************************/
@@ -1027,7 +1095,7 @@
 		rc = slot_update (&tmp_slot);
 		if (rc)
 			return 0;
-		if (SLOT_PRESENT (tmp_slot->status) && SLOT_POWER (tmp_slot->status))
+		if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status))
 			return 0;
 		i++;
 	}
@@ -1036,13 +1104,18 @@
 
 /***********************************************************
  * If the HPC permits and the bus currently empty, tries to set the 
- * bus speed and mode at the maximum card capability
+ * bus speed and mode at the maximum card and bus capability
+ * Parameters: slot
+ * Returns: bus is set (0) or error code
  ***********************************************************/
 static int set_bus (struct slot * slot_cur)
 {
 	int rc;
 	u8 speed;
 	u8 cmd = 0x0;
+	const struct list_head *tmp;
+	struct pci_dev * dev;
+	int retval;
 
 	debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number);
 	if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) {
@@ -1056,30 +1129,118 @@
 			cmd = HPC_BUS_33CONVMODE;
 			break;
 		case HPC_SLOT_SPEED_66:
-			if (SLOT_PCIX (slot_cur->ext_status))
-				cmd = HPC_BUS_66PCIXMODE;
-			else
-				cmd = HPC_BUS_66CONVMODE;
+			if (SLOT_PCIX (slot_cur->ext_status)) {
+				if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX))
+					cmd = HPC_BUS_66PCIXMODE;
+				else if (!SLOT_BUS_MODE (slot_cur->ext_status))
+					/* if max slot/bus capability is 66 pci
+					and there's no bus mode mismatch, then
+					the adapter supports 66 pci */ 
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			} else {
+				if (slot_cur->supported_speed >= BUS_SPEED_66)
+					cmd = HPC_BUS_66CONVMODE;
+				else
+					cmd = HPC_BUS_33CONVMODE;
+			}
 			break;
 		case HPC_SLOT_SPEED_133:
-			if (slot_cur->bus_on->slot_count > 1)
+			switch (slot_cur->supported_speed) {
+			case BUS_SPEED_33:
+				cmd = HPC_BUS_33CONVMODE;
+				break;
+			case BUS_SPEED_66:
+				if (slot_cur->supported_bus_mode == BUS_MODE_PCIX)
+					cmd = HPC_BUS_66PCIXMODE;
+				else
+					cmd = HPC_BUS_66CONVMODE;
+				break;
+			case BUS_SPEED_100:
 				cmd = HPC_BUS_100PCIXMODE;
-			else
+				break;
+			case BUS_SPEED_133:
+				/* This is to take care of the bug in CIOBX chip*/
+				list_for_each (tmp, &pci_devices) {
+					dev = (struct pci_dev *) pci_dev_g (tmp);
+					if (dev) {
+						if ((dev->vendor == 0x1166) && (dev->device == 0x0101))
+							ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE);
+					}
+				}
 				cmd = HPC_BUS_133PCIXMODE;
+				break;
+			default:
+				err ("Wrong bus speed \n");
+				return -ENODEV;
+			}
 			break;
 		default:
 			err ("wrong slot speed \n");
 			return -ENODEV;
 		}
 		debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd);
-		rc = ibmphp_hpc_writeslot (slot_cur, cmd);
-		if (rc)
-			return rc;
+		retval = ibmphp_hpc_writeslot (slot_cur, cmd);
+		if (retval) {
+			err ("setting bus speed failed\n");
+			return retval;
+		}
+		if (CTLR_RESULT (slot_cur->ctrl->status)) {
+			err ("command not completed successfully in set_bus \n");
+			return -EIO;
+		}
 	}
+	/* This is for x440, once Brandon fixes the firmware, 
+	will not need this delay */
+	long_delay (1 * HZ);
 	debug ("%s -Exit \n", __FUNCTION__);
 	return 0;
 }
 
+/* This routine checks the bus limitations that the slot is on from the BIOS.
+ * This is used in deciding whether or not to power up the slot.  
+ * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on
+ * same bus) 
+ * Parameters: slot
+ * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus
+ */
+static int check_limitations (struct slot *slot_cur)
+{
+	u8 i;
+	struct slot * tmp_slot;
+	u8 count = 0;
+	u8 limitation = 0;
+
+	for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) {
+		tmp_slot = ibmphp_get_slot_from_physical_num (i);
+		if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) 
+			count++;
+	}
+	get_cur_bus_info (&slot_cur);
+	switch (slot_cur->bus_on->current_speed) {
+	case BUS_SPEED_33:
+		limitation = slot_cur->bus_on->slots_at_33_conv;
+		break;
+	case BUS_SPEED_66:
+		if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX)
+			limitation = slot_cur->bus_on->slots_at_66_pcix;
+		else
+			limitation = slot_cur->bus_on->slots_at_66_conv;
+		break;
+	case BUS_SPEED_100:
+		limitation = slot_cur->bus_on->slots_at_100_pcix;
+		break;
+	case BUS_SPEED_133:
+		limitation = slot_cur->bus_on->slots_at_133_pcix;
+		break;
+	}
+
+	if ((count + 1) > limitation)
+		return -EINVAL;
+	return 0;
+}
+
 static inline void print_card_capability (struct slot *slot_cur)
 {
 	info ("capability of the card is ");
@@ -1136,7 +1297,28 @@
 		ibmphp_unlock_operations ();
 		return -ENODEV;
 	}
-		
+
+	/*-----------------debugging------------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); 
+	/*----------------------------------------------------------*/
+
+	rc = check_limitations (slot_cur);
+	if (rc) {
+		err ("Adding this card exceeds the limitations of this bus. \n");
+		err ("(i.e., >1 133MHz cards running on same bus, or >2 66 PCI cards running on same bus \n. Try hot-adding into another bus \n");
+		attn_off (slot_cur);
+		attn_on (slot_cur);
+
+		if (slot_update (&slot_cur)) {
+			ibmphp_unlock_operations ();
+			return -ENODEV;
+		}
+		ibmphp_update_slot_info (slot_cur);
+		ibmphp_unlock_operations ();
+		return -EINVAL;
+	}
+
 	rc = power_on (slot_cur);
 
 	if (rc) {
@@ -1151,19 +1333,24 @@
 			return -ENODEV;
 		}
 		/* Check to see the error of why it failed */
-		if (!(SLOT_PWRGD (slot_cur->status)))
+		if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status)))
 			err ("power fault occured trying to power up \n");
 		else if (SLOT_BUS_SPEED (slot_cur->status)) {
 			err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
 			print_card_capability (slot_cur);
-		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) 
+		} else if (SLOT_BUS_MODE (slot_cur->ext_status)) {
 			err ("bus mode mismatch occured.  please check current bus mode and card capability \n");
-
+			print_card_capability (slot_cur);
+		}
 		ibmphp_update_slot_info (slot_cur);
-		ibmphp_unlock_operations (); 
+		ibmphp_unlock_operations ();
 		return rc;
 	}
 	debug ("after power_on\n");
+	/*-----------------------debugging---------------------------*/
+	get_cur_bus_info (&slot_cur);
+	debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed);
+	/*----------------------------------------------------------*/
 
 	rc = slot_update (&slot_cur);
 	if (rc) {
@@ -1180,7 +1367,7 @@
 	
 	if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) {
 		faulted = 1;
-		err ("power fault occured trying to power up...\n");
+		err ("power fault occured trying to power up... \n");
 	} else if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) {
 		faulted = 1;
 		err ("bus speed mismatch occured.  please check current bus speed and card capability \n");
@@ -1200,8 +1387,8 @@
 			return rcpr;
 		}
 			
-		if (slot_update (&slot_cur)) {
-			ibmphp_unlock_operations ();
+		if (slot_update (&slot_cur)) {                      
+			ibmphp_unlock_operations ();	
 			return -ENODEV;
 		}
 		ibmphp_update_slot_info (slot_cur);
@@ -1278,20 +1465,28 @@
 {
 	int rc;
 	struct slot *slot_cur = (struct slot *) hotplug_slot->private;
-	u8 flag = slot_cur->flag;
+	u8 flag;
+	int parm = 0;
 
-	slot_cur->flag = TRUE;
 	debug ("DISABLING SLOT... \n"); 
 		
-	ibmphp_lock_operations (); 
 	if (slot_cur == NULL) {
-		ibmphp_unlock_operations ();
+		ibmphp_unlock_operations (); 
 		return -ENODEV;
 	}
+	
 	if (slot_cur->ctrl == NULL) {
 		ibmphp_unlock_operations ();
 		return -ENODEV;
 	}
+	
+	flag = slot_cur->flag;	/* to see if got here from polling */
+	
+	if (flag)
+		ibmphp_lock_operations ();
+	
+	slot_cur->flag = TRUE;
+
 	if (flag == TRUE) {
 		rc = validate (slot_cur, DISABLE);	/* checking if powered off already & valid slot # */
 		if (rc) {
@@ -1333,10 +1528,21 @@
 		ibmphp_unlock_operations ();
 		return rc;
 	}
+        
+	/* If we got here from latch suddenly opening on operating card or 
+	a power fault, there's no power to the card, so cannot
+	read from it to determine what resources it occupied.  This operation
+	is forbidden anyhow.  The best we can do is remove it from kernel
+	lists at least */
 
-	rc = ibmphp_unconfigure_card (&slot_cur, 0);
+	if (!flag) {
+		attn_off (slot_cur);
+		return 0;
+	}
+
+	rc = ibmphp_unconfigure_card (&slot_cur, parm);
 	slot_cur->func = NULL;
-	debug ("in disable_slot. after unconfigure_card \n");
+	debug ("in disable_slot. after unconfigure_card\n");
 	if (rc) {
 		err ("could not unconfigure card.\n");
 		attn_off (slot_cur);	/* need to turn off if was blinking b4 */
@@ -1347,9 +1553,8 @@
 			return -EFAULT;
 		}
 
-		if (flag) 
+		if (flag)
 			ibmphp_update_slot_info (slot_cur);
-
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
@@ -1363,9 +1568,7 @@
 			return -EFAULT;
 		}
 
-		if (flag)
-			ibmphp_update_slot_info (slot_cur);
-
+		ibmphp_update_slot_info (slot_cur);
 		ibmphp_unlock_operations ();
 		return rc;
 	}
@@ -1375,30 +1578,26 @@
 		ibmphp_unlock_operations ();
 		return -EFAULT;
 	}
-	if (flag) 
-		rc = ibmphp_update_slot_info (slot_cur);
-	else
-		rc = 0;
-
+	rc = ibmphp_update_slot_info (slot_cur);
 	ibmphp_print_test ();
 	ibmphp_unlock_operations();
 	return rc;
 }
 
 struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
-	owner:				THIS_MODULE,
-	set_attention_status:		set_attention_status,
-	enable_slot:			enable_slot,
-	disable_slot:			ibmphp_disable_slot,
-	hardware_test:			NULL,
-	get_power_status:		get_power_status,
-	get_attention_status:		get_attention_status,
-	get_latch_status:		get_latch_status,
-	get_adapter_status:		get_adapter_present,
-/*	get_max_bus_speed_status:	get_max_bus_speed,
-	get_max_adapter_speed_status:	get_max_adapter_speed,
-	get_cur_bus_speed_status:	get_cur_bus_speed,
-	get_card_bus_names_status:	get_card_bus_names,
+	.owner =			THIS_MODULE,
+	.set_attention_status =		set_attention_status,
+	.enable_slot =			enable_slot,
+	.disable_slot =			ibmphp_disable_slot,
+	.hardware_test =		NULL,
+	.get_power_status =		get_power_status,
+	.get_attention_status =		get_attention_status,
+	.get_latch_status =		get_latch_status,
+	.get_adapter_status =		get_adapter_present,
+	.get_max_bus_speed =		get_max_bus_speed,
+	.get_cur_bus_speed =		get_cur_bus_speed,
+/*	.get_max_adapter_speed =	get_max_adapter_speed,
+	.get_bus_name_status =		get_bus_name,
 */
 };
 
@@ -1422,9 +1621,12 @@
 	int rc = 0;
 
 	init_flag = 1;
+
+	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
 	ibmphp_pci_root_ops = get_root_pci_ops ();
 	if (ibmphp_pci_root_ops == NULL) {
-		err ("cannot read bus operations... will not be able to read the cards.  Please check your system \n");
+		err ("cannot read bus operations... will not be able to read the cards.  Please check your system\n");
 		return -ENODEV;	
 	}
 
@@ -1439,15 +1641,20 @@
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("after ibmphp_access_ebda () \n");
+	debug ("after ibmphp_access_ebda ()\n");
 
 	if ((rc = ibmphp_rsrc_init ())) {
 		ibmphp_unload ();
 		return rc;
 	}
-	debug ("AFTER Resource & EBDA INITIALIZATIONS \n");
+	debug ("AFTER Resource & EBDA INITIALIZATIONS\n");
 
 	max_slots = get_max_slots ();
+	
+	if ((rc = ibmphp_register_pci ())) {
+		ibmphp_unload ();
+		return rc;
+	}
 
 	if (init_ops ()) {
 		ibmphp_unload ();
@@ -1459,21 +1666,18 @@
 		return -ENODEV;
 	}
 
-	/* lock ourselves into memory with a module count of -1 
-	 * so that no one can unload us. */
+	/* if no NVRAM module selected, lock ourselves into memory with a 
+	 * module count of -1 so that no one can unload us. */
 	MOD_DEC_USE_COUNT;
-
-	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
-
 	return 0;
 }
 
 static void __exit ibmphp_exit (void)
 {
 	ibmphp_hpc_stop_poll_thread ();
-	debug ("after polling \n");
+	debug ("after polling\n");
 	ibmphp_unload ();
-	debug ("done \n");
+	debug ("done\n");
 }
 
 module_init (ibmphp_init);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)