[prev in list] [next in list] [prev in thread] [next in thread] 

List:       git-commits-24
Subject:    [PATCH] PCI Hotplug: acpiphp unable to power off slots
From:       Linux Kernel Mailing List <linux-kernel () vger ! kernel ! org>
Date:       2004-03-31 23:29:24
Message-ID: 200405211104.i4LB4AJ7009933 () hera ! kernel ! org
[Download RAW message or body]

ChangeSet 1.1267.48.2, 2004/03/31 15:29:24-08:00, t-kochi@bq.jp.nec.com

	[PATCH] PCI Hotplug: acpiphp unable to power off slots
	
	Hi Greg,
	
	Here's acpiphp updates for 2.4 (cleanup patch + changes
	from 2.6).
	
	From: Takayoshi Kochi <t-kochi@bq.jp.nec.com>
	Subject: Re: [Pcihpd-discuss] acpiphp unable to power off slots
	Date: Fri, 05 Mar 2004 19:37:37 +0900 (JST)
	
	> Hi Gary,
	>
	> Thanks for looking at the problem.  I greatly appreciate that.
	> Your analysis and fix looks correct to me.
	>
	> I had a luck to test on the real machine (ia64) today and
	> tested the patch with your previous I/O space patch.
	> I confirmed it works for an e100 card.
	>
	> Attached patch includes the I/O space fix and applies to 2.6.3.
	> This should also solve the problem Maeda-san reported in January
	> (sorry for replying so late!)
	>
	> Here are changes in the patch:
	>
	>  - fix the acpiphp driver not powering down a PCI card (from Gary Hade)
	>  - fix I/O space size calculation and ISA aliasing (from Gary Hade)
	>  - fix some debug messages
	>  - only execute ACPI methods on the first existing function
	>
	> Greg, could you pick this up?
	> Then I'll rework the pending 2.4 patch.
	>
	> From: Gary Hade <garyhade@us.ibm.com>
	> Subject: [Pcihpd-discuss] acpiphp unable to power off slots
	> Date: Thu, 4 Mar 2004 18:09:09 -0800
	>
	> > Kochi-san,
	> > While verifying that the PCI hotplug support in SLES9 Preview 2
	> > for ia64 (based on 2.6.2 kernel) was working correctly I discovered
	> > that it was impossible to power off a PCI adapter containing slots
	> > by echoing 0 to the power file.  While the slot power off problem
	> > that I previously reported only appeared to happen only with cards
	> > containing a PCI-to-PCI bridge, the current problem happens with
	> > _any_ PCI adapter.
	> >
	> > After some investigation I believe I found a flaw in the fix you
	> > provided for the previously reported slow power off problem.  Within
	> > power_off_slot() the following expressions will always be false
	> > because func->pci_dev will always be set to NULL during an earlier
	> > call to disable_device().
	> >    (func->pci_dev && (func->flags & FUNC_HAS_PS3)
	> >    (func->pci_dev && (func->flags & FUNC_HAS_EJ0)
	> > As a result, acpi_evaluate_object() is never called to power
	> > down the slot.
	> >
	> > Below is a possible fix for the problem.  Please review as soon
	> > as possible.



 acpiphp.h          |    5 +--
 acpiphp_core.c     |   30 ++++++++++++++++++++---
 acpiphp_glue.c     |   56 +++++++++++++++++++++++++------------------
 acpiphp_pci.c      |   18 ++++++-------
 acpiphp_res.c      |    5 +--
 pci_hotplug.h      |    6 ++++
 pci_hotplug_core.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 148 insertions(+), 41 deletions(-)


diff -Nru a/drivers/hotplug/acpiphp.h b/drivers/hotplug/acpiphp.h
--- a/drivers/hotplug/acpiphp.h	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/acpiphp.h	2004-05-21 04:04:13 -07:00
@@ -202,7 +202,7 @@
 
 #define SLOT_POWEREDON		(0x00000001)
 #define SLOT_ENABLED		(0x00000002)
-#define SLOT_MULTIFUNCTION	(x000000004)
+#define SLOT_MULTIFUNCTION	(0x00000004)
 
 /* function flags */
 
@@ -213,8 +213,6 @@
 #define FUNC_HAS_PS2		(0x00000040)
 #define FUNC_HAS_PS3		(0x00000080)
 
-#define FUNC_EXISTS		(0x10000000) /* to make sure we call _EJ0 only for existing funcs */
-
 /* function prototypes */
 
 /* acpiphp_glue.c */
@@ -232,6 +230,7 @@
 extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
 extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
 extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
+extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
 
 /* acpiphp_pci.c */
 extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
diff -Nru a/drivers/hotplug/acpiphp_core.c b/drivers/hotplug/acpiphp_core.c
--- a/drivers/hotplug/acpiphp_core.c	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/acpiphp_core.c	2004-05-21 04:04:13 -07:00
@@ -30,14 +30,14 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
+
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
@@ -73,6 +73,7 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_address		(struct hotplug_slot *slot, u32 *value);
 static int get_max_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 static int get_cur_bus_speed	(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value);
 
@@ -86,6 +87,7 @@
 	.get_attention_status	= get_attention_status,
 	.get_latch_status	= get_latch_status,
 	.get_adapter_status	= get_adapter_status,
+	.get_address		= get_address,
 	.get_max_bus_speed	= get_max_bus_speed,
 	.get_cur_bus_speed	= get_cur_bus_speed,
 };
@@ -317,6 +319,28 @@
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	*value = acpiphp_get_adapter_status(slot->acpi_slot);
+
+	return retval;
+}
+
+
+/**
+ * get_address - get pci address of a slot
+ * @hotplug_slot: slot to get status
+ * @busdev: pointer to struct pci_busdev (seg, bus, dev)
+ *
+ */
+static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+	int retval = 0;
+
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_address(slot->acpi_slot);
 
 	return retval;
 }
diff -Nru a/drivers/hotplug/acpiphp_glue.c b/drivers/hotplug/acpiphp_glue.c
--- a/drivers/hotplug/acpiphp_glue.c	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/acpiphp_glue.c	2004-05-21 04:04:13 -07:00
@@ -26,12 +26,12 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
+
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>
 #include <asm/semaphore.h>
 
 #include "pci_hotplug.h"
@@ -783,7 +783,7 @@
 	struct list_head *l;
 	int retval = 0;
 
-	/* is this already enabled? */
+	/* if already enabled, just skip */
 	if (slot->flags & SLOT_POWEREDON)
 		goto err_exit;
 
@@ -791,14 +791,14 @@
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_PS0) {
-			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
-			    func->pci_dev->slot_name);
+			dbg("%s: executing _PS0\n", __FUNCTION__);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -821,20 +821,21 @@
 
 	int retval = 0;
 
-	/* is this already enabled? */
+	/* if already disabled, just skip */
 	if ((slot->flags & SLOT_POWEREDON) == 0)
 		goto err_exit;
 
 	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
-		if (func->flags & (FUNC_HAS_PS3 | FUNC_EXISTS)) {
+		if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) {
 			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -842,20 +843,19 @@
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		/* We don't want to call _EJ0 on non-existing functions. */
-		if (func->flags & (FUNC_HAS_EJ0 | FUNC_EXISTS)) {
+		if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) {
 			/* _EJ0 method take one argument */
 			arg_list.count = 1;
 			arg_list.pointer = &arg;
 			arg.type = ACPI_TYPE_INTEGER;
 			arg.integer.value = 1;
-
 			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
 				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
-			func->flags &= (~FUNC_EXISTS);
+			} else
+				break;
 		}
 	}
 
@@ -937,8 +937,6 @@
 		retval = acpiphp_configure_function(func);
 		if (retval)
 			goto err_exit;
-
-		func->flags |= FUNC_EXISTS;
 	}
 
 	slot->flags |= SLOT_ENABLED;
@@ -967,15 +965,12 @@
 	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
-		if (func->pci_dev) {
-			if (acpiphp_unconfigure_function(func) == 0) {
-				func->pci_dev = NULL;
-			} else {
+		if (func->pci_dev)
+			if (acpiphp_unconfigure_function(func)) {
 				err("failed to unconfigure device\n");
 				retval = -1;
 				goto err_exit;
 			}
-		}
 	}
 
 	slot->flags &= (~SLOT_ENABLED);
@@ -1355,7 +1350,7 @@
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				enabled++;
+				disabled++;
 			}
 		} else {
 			/* if disabled but present, enable */
@@ -1366,7 +1361,7 @@
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				disabled++;
+				enabled++;
 			}
 		}
 	}
@@ -1431,4 +1426,19 @@
 	sta = get_slot_status(slot);
 
 	return (sta == 0) ? 0 : 1;
+}
+
+
+/*
+ * pci address (seg/bus/dev)
+ */
+u32 acpiphp_get_address (struct acpiphp_slot *slot)
+{
+	u32 address;
+
+	address = ((slot->bridge->seg) << 16) |
+		  ((slot->bridge->bus) << 8) |
+		  slot->device;
+
+	return address;
 }
diff -Nru a/drivers/hotplug/acpiphp_pci.c b/drivers/hotplug/acpiphp_pci.c
--- a/drivers/hotplug/acpiphp_pci.c	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/acpiphp_pci.c	2004-05-21 04:04:13 -07:00
@@ -29,11 +29,11 @@
  *
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
+#include <linux/init.h>
 #include <linux/module.h>
+
+#include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include "pci_hotplug.h"
 #include "acpiphp.h"
 
@@ -78,8 +78,8 @@
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 
-			len = bar & 0xFFFFFFFC;
-			len = ~len + 1;
+			len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("len in IO %x, BAR %d\n", len, count);
 
@@ -340,8 +340,8 @@
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 			base = bar & 0xFFFFFFFC;
-			len &= 0xFFFFFFFC;
-			len = ~len + 1;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
@@ -465,8 +465,8 @@
 		if (len & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
 			base = bar & 0xFFFFFFFC;
-			len &= 0xFFFFFFFC;
-			len = ~len + 1;
+			len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
+			len = len & ~(len - 1);
 
 			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
diff -Nru a/drivers/hotplug/acpiphp_res.c b/drivers/hotplug/acpiphp_res.c
--- a/drivers/hotplug/acpiphp_res.c	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/acpiphp_res.c	2004-05-21 04:04:13 -07:00
@@ -29,7 +29,7 @@
  *
  */
 
-#include <linux/config.h>
+#include <linux/init.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -39,7 +39,6 @@
 #include <linux/pci.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>
 
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -225,7 +224,7 @@
 		}  /* End of too big on top end */
 
 		/* For IO make sure it's not in the ISA aliasing space */
-		if (node->base & 0x300L)
+		if ((node->base & 0x300L) && !(node->base & 0xfffff000))
 			continue;
 
 		/* If we got here, then it is the right size
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/pci_hotplug.h	2004-05-21 04:04:13 -07:00
@@ -69,6 +69,9 @@
  * @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_address: Called to get pci address 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_max_bus_speed: 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.
@@ -91,6 +94,7 @@
 	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_address)		(struct hotplug_slot *slot, u32 *value);
 	int (*get_max_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 	int (*get_cur_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 };
@@ -101,6 +105,7 @@
  * @attention_status: if the attention light is enabled or not (1/0)
  * @latch_status: if the latch (if any) is open or closed (1/0)
  * @adapter_present: if there is a pci board present in the slot or not (1/0)
+ * @address: (domain << 16 | bus << 8 | dev)
  *
  * Used to notify the hotplug pci core of the status of a specific slot.
  */
@@ -109,6 +114,7 @@
 	u8	attention_status;
 	u8	latch_status;
 	u8	adapter_status;
+	u32	address;
 	enum pci_bus_speed	max_bus_speed;
 	enum pci_bus_speed	cur_bus_speed;
 };
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	2004-05-21 04:04:13 -07:00
+++ b/drivers/hotplug/pci_hotplug_core.c	2004-05-21 04:04:13 -07:00
@@ -74,6 +74,7 @@
 	struct dentry	*attention_dentry;
 	struct dentry	*latch_dentry;
 	struct dentry	*adapter_dentry;
+	struct dentry	*address_dentry;
 	struct dentry	*test_dentry;
 	struct dentry	*max_bus_speed_dentry;
 	struct dentry	*cur_bus_speed_dentry;
@@ -312,6 +313,15 @@
 	llseek:		default_file_lseek,
 };
 
+/* file ops for the "address" files */
+static ssize_t address_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations address_file_operations = {
+	read:		address_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	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 = {
@@ -566,6 +576,7 @@
 GET_STATUS(attention_status, u8)
 GET_STATUS(latch_status, u8)
 GET_STATUS(adapter_status, u8)
+GET_STATUS(address, u32)
 GET_STATUS(max_bus_speed, enum pci_bus_speed)
 GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
@@ -859,6 +870,52 @@
 	return retval;
 }
 
+static ssize_t address_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	int retval;
+	int len;
+	u32 address;
+
+	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_address (slot, &address);
+	if (retval)
+		goto exit;
+	len = sprintf (page, "%04x:%02x:%02x\n",
+		       (address >> 16) & 0xffff,
+		       (address >> 8) & 0xff,
+		       address & 0xff);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	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)
@@ -1055,6 +1112,13 @@
 						core->dir_dentry, slot,
 						&presence_file_operations);
 
+		if (slot->ops->get_address)
+			core->address_dentry = 
+				fs_create_file ("address",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&address_file_operations);
+
 		if (slot->ops->get_max_bus_speed)
 			core->max_bus_speed_dentry = 
 				fs_create_file ("max_bus_speed",
@@ -1092,6 +1156,8 @@
 			fs_remove_file (core->latch_dentry);
 		if (core->adapter_dentry)
 			fs_remove_file (core->adapter_dentry);
+		if (core->address_dentry)
+			fs_remove_file (core->address_dentry);
 		if (core->max_bus_speed_dentry)
 			fs_remove_file (core->max_bus_speed_dentry);
 		if (core->cur_bus_speed_dentry)
@@ -1243,6 +1309,9 @@
 	if ((core->adapter_dentry) &&
 	    (temp->info->adapter_status != info->adapter_status))
 		update_dentry_inode_time (core->adapter_dentry);
+	if ((core->address_dentry) &&
+	    (temp->info->address != info->address))
+		update_dentry_inode_time (core->address_dentry);
 	if ((core->cur_bus_speed_dentry) &&
 	    (temp->info->cur_bus_speed != info->cur_bus_speed))
 		update_dentry_inode_time (core->cur_bus_speed_dentry);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-24" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic