# This is a BitKeeper generated patch for the following project:
# Project Name: greg k-h's linux 2.5 USB kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.814   -> 1.819  
#	      kernel/ksyms.c	1.49    -> 1.51   
#	drivers/hotplug/pci_hotplug.h	1.3     -> 1.4    
#	drivers/hotplug/pci_hotplug_core.c	1.22    -> 1.24   
#	drivers/hotplug/ibmphp_core.c	1.11    -> 1.12   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/09/17	scottm@somanetworks.com	1.815
# [PATCH] Small pcihpfs dnotify fix
# 
# I've been working on a userspace daemon to go with my CompactPCI driver,
# and yesterday I discovered an oversight in pci_hp_change_slot_info - it
# doesn't call dnotify_parent, so dnotify based clients basically don't
# work against pcihpfs.  The following patch (against 2.5 BK) reworks
# things to just update the mtime (since we're modifying the file after
# all), and then call dnotify_parent.
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.816
# added max bus speed and current bus speed files to the pci hotplug core.
# 
# Patch based on work done by Irene Zubarev <zubarev@us.ibm.com>
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.817
# uncommented max bus speed and current bus speed functions from the ibm pci hotplug driver
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.818
# added __inode_dir_notify to the list of exported symbols so that dnotify_parent()
# can be called from a module.
# --------------------------------------------
# 02/09/17	greg@kroah.com	1.819
# forgot to include dnotify.h in ksyms.c :(
# --------------------------------------------
#
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Tue Sep 17 17:06:43 2002
+++ b/drivers/hotplug/ibmphp_core.c	Tue Sep 17 17:06:43 2002
@@ -384,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 ();
 
@@ -413,25 +414,26 @@
 				*value = pslot->supported_speed + 0x01;
 				break;
 			default:
-*/				/* Note (will need to change): there would be soon 256, 512 also */
-/*				rc = -ENODEV;
+				/* 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 ();
 
@@ -458,8 +460,8 @@
 					*value += 0x01;
 					break;
 				default:
-*/					/* Note of change: there would also be 256, 512 soon */
-/*					rc = -ENODEV;
+					/* Note of change: there would also be 256, 512 soon */
+					rc = -ENODEV;
 				}
 			}
 		}
@@ -467,10 +469,10 @@
 		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;
@@ -1584,9 +1586,9 @@
 	.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_max_bus_speed_status =	get_max_bus_speed,
 	.get_cur_bus_speed_status =	get_cur_bus_speed,
+/*	.get_max_adapter_speed_status =	get_max_adapter_speed,
 	.get_bus_name_status =		get_bus_name,
 */
 };
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	Tue Sep 17 17:06:43 2002
+++ b/drivers/hotplug/pci_hotplug.h	Tue Sep 17 17:06:43 2002
@@ -29,6 +29,22 @@
 #define _PCI_HOTPLUG_H
 
 
+/* These values come from the PCI Hotplug Spec */
+enum pci_bus_speed {
+	PCI_SPEED_33MHz			= 0x00,
+	PCI_SPEED_66MHz			= 0x01,
+	PCI_SPEED_66MHz_PCIX		= 0x02,
+	PCI_SPEED_100MHz_PCIX		= 0x03,
+	PCI_SPEED_133MHz_PCIX		= 0x04,
+	PCI_SPEED_66MHz_PCIX_266	= 0x09,
+	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
+	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
+	PCI_SPEED_66MHz_PCIX_533	= 0x11,
+	PCI_SPEED_100MHz_PCIX_533	= 0X12,
+	PCI_SPEED_133MHz_PCIX_533	= 0x13,
+	PCI_SPEED_UNKNOWN		= 0xff,
+};
+
 struct hotplug_slot;
 struct hotplug_slot_core;
 
@@ -50,7 +66,13 @@
  * @get_latch_status: Called to get the current latch status of a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
- * @get_adapter_present: Called to get see if an adapter is present in the slot or not.
+ * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_max_bus_speed_status: Called to get the max bus speed for a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_cur_bus_speed_status: Called to get the current bus speed for a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
  *
@@ -69,6 +91,8 @@
 	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
 	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
 	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_max_bus_speed_status)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+	int (*get_cur_bus_speed_status)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 };
 
 /**
@@ -85,6 +109,8 @@
 	u8	attention_status;
 	u8	latch_status;
 	u8	adapter_status;
+	enum pci_bus_speed	max_bus_speed_status;
+	enum pci_bus_speed	cur_bus_speed_status;
 };
 
 /**
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Tue Sep 17 17:06:43 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Tue Sep 17 17:06:43 2002
@@ -38,6 +38,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/pci.h>
+#include <linux/dnotify.h>
 #include <asm/uaccess.h>
 #include "pci_hotplug.h"
 
@@ -74,6 +75,8 @@
 	struct dentry	*latch_dentry;
 	struct dentry	*adapter_dentry;
 	struct dentry	*test_dentry;
+	struct dentry	*max_bus_speed_dentry;
+	struct dentry	*cur_bus_speed_dentry;
 };
 
 static struct super_operations pcihpfs_ops;
@@ -86,6 +89,29 @@
 
 LIST_HEAD(pci_hotplug_slot_list);
 
+/* these strings match up with the values in pci_bus_speed */
+static char *pci_bus_speed_strings[] = {
+	"33 MHz PCI",		/* 0x00 */
+	"66 MHz PCI",		/* 0x01 */
+	"66 MHz PCIX", 		/* 0x02 */
+	"100 MHz PCIX",		/* 0x03 */
+	"133 MHz PCIX",		/* 0x04 */
+	NULL,			/* 0x05 */
+	NULL,			/* 0x06 */
+	NULL,			/* 0x07 */
+	NULL,			/* 0x08 */
+	"66 MHz PCIX 266",	/* 0x09 */
+	"100 MHz PCIX 266",	/* 0x0a */
+	"133 MHz PCIX 266",	/* 0x0b */
+	NULL,			/* 0x0c */
+	NULL,			/* 0x0d */
+	NULL,			/* 0x0e */
+	NULL,			/* 0x0f */
+	NULL,			/* 0x10 */
+	"66 MHz PCIX 533",	/* 0x11 */
+	"100 MHz PCIX 533",	/* 0x12 */
+	"133 MHz PCIX 533",	/* 0x13 */
+};
 
 static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev)
 {
@@ -274,6 +300,24 @@
 	.llseek =	default_file_lseek,
 };
 
+/* file ops for the "max bus speed" files */
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations max_bus_speed_file_operations = {
+	read:		max_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
+/* file ops for the "current bus speed" files */
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations cur_bus_speed_file_operations = {
+	read:		cur_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
 /* file ops for the "test" files */
 static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
 static struct file_operations test_file_operations = {
@@ -501,8 +545,8 @@
 	up(&parent->d_inode->i_sem);
 }
 
-#define GET_STATUS(name)	\
-static int get_##name##_status (struct hotplug_slot *slot, u8 *value)	\
+#define GET_STATUS(name,type)	\
+static int get_##name##_status (struct hotplug_slot *slot, type *value)	\
 {									\
 	struct hotplug_slot_ops *ops = slot->ops;			\
 	int retval = 0;							\
@@ -517,10 +561,12 @@
 	return retval;							\
 }
 
-GET_STATUS(power)
-GET_STATUS(attention)
-GET_STATUS(latch)
-GET_STATUS(adapter)
+GET_STATUS(power, u8)
+GET_STATUS(attention, u8)
+GET_STATUS(latch, u8)
+GET_STATUS(adapter, u8)
+GET_STATUS(max_bus_speed, enum pci_bus_speed)
+GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
 static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
@@ -769,7 +815,6 @@
 	return retval;
 }
 
-
 static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -813,6 +858,108 @@
 	return retval;
 }
 
+static char *unknown_speed = "Unknown bus speed";
+
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+	
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_max_bus_speed_status (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_cur_bus_speed_status (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
 static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -876,30 +1023,57 @@
 					   S_IFDIR | S_IXUGO | S_IRUGO,
 					   NULL, NULL, NULL);
 	if (core->dir_dentry != NULL) {
-		core->power_dentry = fs_create_file ("power",
-						     S_IFREG | S_IRUGO | S_IWUSR,
-						     core->dir_dentry, slot,
-						     &power_file_operations);
-
-		core->attention_dentry = fs_create_file ("attention",
-							 S_IFREG | S_IRUGO | S_IWUSR,
-							 core->dir_dentry, slot,
-							 &attention_file_operations);
-
-		core->latch_dentry = fs_create_file ("latch",
-						     S_IFREG | S_IRUGO,
-						     core->dir_dentry, slot,
-						     &latch_file_operations);
-
-		core->adapter_dentry = fs_create_file ("adapter",
-						       S_IFREG | S_IRUGO,
-						       core->dir_dentry, slot,
-						       &presence_file_operations);
-
-		core->test_dentry = fs_create_file ("test",
-						    S_IFREG | S_IRUGO | S_IWUSR,
-						    core->dir_dentry, slot,
-						    &test_file_operations);
+		if ((slot->ops->enable_slot) ||
+		    (slot->ops->disable_slot) ||
+		    (slot->ops->get_power_status))
+			core->power_dentry = 
+				fs_create_file ("power",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&power_file_operations);
+
+		if ((slot->ops->set_attention_status) ||
+		    (slot->ops->get_attention_status))
+			core->attention_dentry =
+				fs_create_file ("attention",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&attention_file_operations);
+
+		if (slot->ops->get_latch_status)
+			core->latch_dentry = 
+				fs_create_file ("latch",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&latch_file_operations);
+
+		if (slot->ops->get_adapter_status)
+			core->adapter_dentry = 
+				fs_create_file ("adapter",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&presence_file_operations);
+
+		if (slot->ops->get_max_bus_speed_status)
+			core->max_bus_speed_dentry = 
+				fs_create_file ("max_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&max_bus_speed_file_operations);
+
+		if (slot->ops->get_cur_bus_speed_status)
+			core->cur_bus_speed_dentry =
+				fs_create_file ("cur_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&cur_bus_speed_file_operations);
+
+		if (slot->ops->hardware_test)
+			core->test_dentry =
+				fs_create_file ("test",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&test_file_operations);
 	}
 	return 0;
 }
@@ -917,6 +1091,10 @@
 			fs_remove_file (core->latch_dentry);
 		if (core->adapter_dentry)
 			fs_remove_file (core->adapter_dentry);
+		if (core->max_bus_speed_dentry)
+			fs_remove_file (core->max_bus_speed_dentry);
+		if (core->cur_bus_speed_dentry)
+			fs_remove_file (core->cur_bus_speed_dentry);
 		if (core->test_dentry)
 			fs_remove_file (core->test_dentry);
 		fs_remove_file (core->dir_dentry);
@@ -969,6 +1147,7 @@
 		return -EINVAL;
 	}
 
+	memset (core, 0, sizeof (struct hotplug_slot_core));
 	slot->core_priv = core;
 
 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
@@ -1012,10 +1191,13 @@
 	return 0;
 }
 
-static inline void update_inode_time (struct inode *inode)
+static inline void update_dentry_inode_time (struct dentry *dentry)
 {
-	if (inode)
-		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	struct inode *inode = dentry->d_inode;
+	if (inode) {
+		inode->i_mtime = CURRENT_TIME;
+		dnotify_parent(dentry, DN_MODIFY);
+	}
 }
 
 /**
@@ -1050,16 +1232,19 @@
 	core = temp->core_priv;
 	if ((core->power_dentry) &&
 	    (temp->info->power_status != info->power_status))
-		update_inode_time (core->power_dentry->d_inode);
+		update_dentry_inode_time (core->power_dentry);
 	if ((core->attention_dentry) &&
 	    (temp->info->attention_status != info->attention_status))
-		update_inode_time (core->attention_dentry->d_inode);
+		update_dentry_inode_time (core->attention_dentry);
 	if ((core->latch_dentry) &&
 	    (temp->info->latch_status != info->latch_status))
-		update_inode_time (core->latch_dentry->d_inode);
+		update_dentry_inode_time (core->latch_dentry);
 	if ((core->adapter_dentry) &&
 	    (temp->info->adapter_status != info->adapter_status))
-		update_inode_time (core->adapter_dentry->d_inode);
+		update_dentry_inode_time (core->adapter_dentry);
+	if ((core->cur_bus_speed_dentry) &&
+	    (temp->info->cur_bus_speed_status != info->cur_bus_speed_status))
+		update_dentry_inode_time (core->cur_bus_speed_dentry);
 
 	memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
 	spin_unlock (&list_lock);
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Sep 17 17:06:43 2002
+++ b/kernel/ksyms.c	Tue Sep 17 17:06:43 2002
@@ -53,6 +53,7 @@
 #include <linux/root_dev.h>
 #include <linux/percpu.h>
 #include <linux/smp_lock.h>
+#include <linux/dnotify.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -559,6 +560,7 @@
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
+EXPORT_SYMBOL(__inode_dir_notify);
 
 #ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);