From: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
To: Alex Chiang <achiang@hp.com>
Cc: Greg KH <gregkh@suse.de>, Jesse Barnes <jbarnes@virtuousgeek.org>,
Matthew Wilcox <matthew@wil.cx>, Gary Hade <garyhade@us.ibm.com>,
warthog19@eaglescrag.net, kristen.c.accardi@intel.com,
rick.jones2@hp.com, linux-kernel@vger.kernel.org,
linux-pci@atrey.karlin.mff.cuni.cz, linux-acpi@vger.kernel.org
Subject: [PATCH 3/(3+1)] ACPI PCI slot detection driver
Date: Tue, 11 Mar 2008 22:13:36 +0900 [thread overview]
Message-ID: <47D68580.6080207@jp.fujitsu.com> (raw)
In-Reply-To: <47D684D0.6060200@jp.fujitsu.com>
v9 -> v10:
Remove DMI quirk for Fujitsu machines; eval _STA before _SUN.
Skip device object whose _STA indicates not present.
v8 -> v9:
Add DMI quirk for Fujitsu machines; eval _STA before _SUN
v6 -> v8:
No change
v5 -> v6:
Add debugging information.
v4 -> v5:
Convert to a tristate module.
Remove #ifdef CONFIG_ACPI_PCI_SLOT, as struct pci_slot
objects are properly refcounted, and multiple calls to
pci_create/destroy_slot work just fine.
Remove prior -EBUSY changes, as they have been folded
into the Introduce pci_slot patch.
v3 -> v4:
Always attempt to call pci_create_slot from pcihp_core to
cover cases of
a) user did not say Y to Kconfig option ACPI_PCI_SLOT
b) native PCIe hotplug driver registering on a
non-ACPI system.
Return -EBUSY if an hp driver attempts to register a slot
that is already registered to another driver. Do not
consider that to be an error condition in acpiphp and pciehp.
v2 -> v3:
Add Kconfig option to driver, allowing users to [de]config
this driver. If configured, take slightly different code
paths in pci_hp_register and pci_hp_deregister.
v1 -> v2:
Now recursively discovering p2p bridges and slots
underneath them. Hopefully, this will prevent us
from trying to register the same slot multiple times.
Signed-off-by: Alex Chiang <achiang@hp.com>
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
---
drivers/acpi/Kconfig | 9
drivers/acpi/Makefile | 1
drivers/acpi/pci_slot.c | 328 +++++++++++++++++++++++++++++++++
drivers/pci/hotplug/pci_hotplug_core.c | 11 +
drivers/pci/hotplug/pciehp_core.c | 2
drivers/pci/hotplug/sgi_hotplug.c | 2
6 files changed, 350 insertions(+), 3 deletions(-)
Index: linux-2.6.25-rc4/drivers/acpi/Kconfig
===================================================================
--- linux-2.6.25-rc4.orig/drivers/acpi/Kconfig
+++ linux-2.6.25-rc4/drivers/acpi/Kconfig
@@ -347,6 +347,15 @@ config ACPI_EC
the battery and thermal drivers. If you are compiling for a
mobile system, say Y.
+config ACPI_PCI_SLOT
+ tristate "PCI slot detection driver"
+ default n
+ help
+ This driver will attempt to discover all PCI slots in your system,
+ and creates entries in /sys/bus/pci/slots/. This feature can
+ help you correlate PCI bus addresses with the physical geography
+ of your slots. If you are unsure, say N.
+
config ACPI_POWER
bool
default y
Index: linux-2.6.25-rc4/drivers/acpi/Makefile
===================================================================
--- linux-2.6.25-rc4.orig/drivers/acpi/Makefile
+++ linux-2.6.25-rc4/drivers/acpi/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o
obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
+obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-$(CONFIG_ACPI_CONTAINER) += container.o
Index: linux-2.6.25-rc4/drivers/acpi/pci_slot.c
===================================================================
--- /dev/null
+++ linux-2.6.25-rc4/drivers/acpi/pci_slot.c
@@ -0,0 +1,328 @@
+/*
+ * pci_slot.c - ACPI PCI Slot Driver
+ *
+ * The code here is heavily leveraged from the acpiphp module.
+ * Thanks to Matthew Wilcox <matthew@wil.cx> for much guidance.
+ *
+ * Copyright (C) 2007 Alex Chiang <achiang@hp.com>
+ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+static int debug;
+
+#define DRIVER_VERSION "0.1"
+#define DRIVER_AUTHOR "Alex Chiang <achiang@hp.com>"
+#define DRIVER_DESC "ACPI PCI Slot Detection Driver"
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+module_param(debug, bool, 0644);
+
+#define _COMPONENT ACPI_PCI_COMPONENT
+ACPI_MODULE_NAME("pci_slot");
+
+#define MY_NAME "pci_slot"
+#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define dbg(format, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "%s: " format, \
+ MY_NAME , ## arg); \
+ } while (0)
+
+static int acpi_pci_slot_add(acpi_handle handle);
+static void acpi_pci_slot_remove(acpi_handle handle);
+
+static struct acpi_pci_driver acpi_pci_slot_driver = {
+ .add = acpi_pci_slot_add,
+ .remove = acpi_pci_slot_remove,
+};
+
+static int
+check_slot(acpi_handle handle, int *device, unsigned long *sun)
+{
+ int retval = 0;
+ unsigned long adr, sta;
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ dbg("Checking slot on path: %s\n", (char *)buffer.pointer);
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && !(sta & ACPI_STA_DEVICE_PRESENT)) {
+ retval = -1;
+ goto out;
+ }
+
+ status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+ if (ACPI_FAILURE(status)) {
+ dbg("_ADR returned %d on %s\n", status, (char *)buffer.pointer);
+ retval = -1;
+ goto out;
+ }
+
+ *device = (adr >> 16) & 0xffff;
+
+ /* No _SUN == not a slot == bail */
+ status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
+ if (ACPI_FAILURE(status)) {
+ dbg("_SUN returned %d on %s\n", status, (char *)buffer.pointer);
+ retval = -1;
+ goto out;
+ }
+
+out:
+ kfree(buffer.pointer);
+ return retval;
+}
+
+/*
+ * unregister_slot
+ *
+ * Called once for each SxFy object in the namespace. Each call to
+ * pci_destroy_slot decrements the refcount on the pci_slot, and
+ * eventually calls kobject_unregister at the appropriate time.
+ */
+static acpi_status
+unregister_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int device;
+ unsigned long sun;
+ struct pci_slot *slot;
+ struct pci_bus *pci_bus = context;
+
+ if (check_slot(handle, &device, &sun))
+ return AE_OK;
+
+ for (slot = pci_bus->slot; slot; slot = slot->next) {
+ if (slot->number == device)
+ pci_destroy_slot(slot);
+ }
+
+ return AE_OK;
+}
+
+/*
+ * register_slot
+ *
+ * Called once for each SxFy object in the namespace. Don't worry about
+ * calling pci_create_slot multiple times for the same pci_bus:device,
+ * since each subsequent call simply bumps the refcount on the pci_slot.
+ *
+ * The number of calls to pci_destroy_slot from unregister_slot is
+ * symmetrical.
+ */
+static acpi_status
+register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int device;
+ unsigned long sun;
+ char name[KOBJ_NAME_LEN];
+
+ struct pci_slot *pci_slot;
+ struct pci_bus *pci_bus = context;
+
+ if (check_slot(handle, &device, &sun))
+ return AE_OK;
+
+ snprintf(name, sizeof(name), "%u", (u32)sun);
+ pci_slot = pci_create_slot(pci_bus, device, name);
+ if (IS_ERR(pci_slot))
+ err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot));
+
+ dbg("pci_slot: %#lx, pci_bus: %x, device: %d, name: %s\n",
+ (uint64_t)pci_slot, pci_bus->number, device, name);
+
+ return AE_OK;
+}
+
+struct p2p_bridge_context
+{
+ acpi_walk_callback user_function;
+ struct pci_bus *pci_bus;
+};
+
+/*
+ * walk_p2p_bridge - discover and walk p2p bridges
+ * @handle: points to an acpi_pci_root
+ * @context: p2p_bridge_context pointer
+ *
+ * Note that when we call ourselves recursively, we pass a different
+ * value of pci_bus in the child_context.
+ */
+static acpi_status
+walk_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int device, function;
+ unsigned long adr;
+ acpi_status status;
+ acpi_handle dummy_handle;
+ acpi_walk_callback user_function;
+
+ struct pci_dev *dev;
+ struct pci_bus *pci_bus;
+ struct p2p_bridge_context child_context;
+ struct p2p_bridge_context *parent_context = context;
+
+ pci_bus = parent_context->pci_bus;
+ user_function = parent_context->user_function;
+
+ status = acpi_get_handle(handle, "_ADR", &dummy_handle);
+ if (ACPI_FAILURE(status))
+ return AE_OK;
+
+ status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
+ if (ACPI_FAILURE(status))
+ return AE_OK;
+
+ device = (adr >> 16) & 0xffff;
+ function = adr & 0xffff;
+
+ dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
+ if (!dev || !dev->subordinate)
+ goto out;
+
+ dbg("p2p bridge walk, pci_bus = %x\n", dev->subordinate->number);
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+ user_function, dev->subordinate, NULL);
+ if (ACPI_FAILURE(status))
+ goto out;
+
+ child_context.pci_bus = dev->subordinate;
+ child_context.user_function = user_function;
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+ walk_p2p_bridge, &child_context, NULL);
+out:
+ pci_dev_put(dev);
+ return AE_OK;
+}
+
+#define ACPI_STA_FUNCTIONING (0x00000008)
+
+/*
+ * walk_root_bridge - generic root bridge walker
+ * @handle: points to an acpi_pci_root
+ * @user_function: user callback for slot objects
+ *
+ * Call user_function for all objects underneath this root bridge.
+ * Walk p2p bridges underneath us and call user_function on those too.
+ */
+static int
+walk_root_bridge(acpi_handle handle, acpi_walk_callback user_function)
+{
+ int seg, bus;
+ unsigned long tmp;
+ acpi_status status;
+ acpi_handle dummy_handle;
+ struct pci_bus *pci_bus;
+ struct p2p_bridge_context context;
+
+ /* If the bridge doesn't have _STA, we assume it is always there */
+ status = acpi_get_handle(handle, "_STA", &dummy_handle);
+ if (ACPI_SUCCESS(status)) {
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
+ if (ACPI_FAILURE(status)) {
+ info("%s: _STA evaluation failure\n", __FUNCTION__);
+ return 0;
+ }
+ if ((tmp & ACPI_STA_FUNCTIONING) == 0)
+ /* don't register this object */
+ return 0;
+ }
+
+ status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp);
+ seg = ACPI_SUCCESS(status) ? tmp : 0;
+
+ status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp);
+ bus = ACPI_SUCCESS(status) ? tmp : 0;
+
+ pci_bus = pci_find_bus(seg, bus);
+ if (!pci_bus)
+ return 0;
+
+ dbg("root bridge walk, pci_bus = %x\n", pci_bus->number);
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+ user_function, pci_bus, NULL);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ context.pci_bus = pci_bus;
+ context.user_function = user_function;
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
+ walk_p2p_bridge, &context, NULL);
+ if (ACPI_FAILURE(status))
+ err("%s: walk_p2p_bridge failure - %d\n", __FUNCTION__, status);
+
+ return status;
+}
+
+/*
+ * acpi_pci_slot_add
+ * @handle: points to an acpi_pci_root
+ */
+static int
+acpi_pci_slot_add(acpi_handle handle)
+{
+ acpi_status status;
+
+ status = walk_root_bridge(handle, register_slot);
+ if (ACPI_FAILURE(status))
+ err("%s: register_slot failure - %d\n", __FUNCTION__, status);
+
+ return status;
+}
+
+/*
+ * acpi_pci_slot_remove
+ * @handle: points to an acpi_pci_root
+ */
+static void
+acpi_pci_slot_remove(acpi_handle handle)
+{
+ acpi_status status;
+
+ status = walk_root_bridge(handle, unregister_slot);
+ if (ACPI_FAILURE(status))
+ err("%s: unregister_slot failure - %d\n", __FUNCTION__, status);
+}
+
+static int __init
+acpi_pci_slot_init(void)
+{
+ acpi_pci_register_driver(&acpi_pci_slot_driver);
+ return 0;
+}
+
+static void __exit
+acpi_pci_slot_exit(void)
+{
+ acpi_pci_unregister_driver(&acpi_pci_slot_driver);
+}
+
+module_init(acpi_pci_slot_init);
+module_exit(acpi_pci_slot_exit);
Index: linux-2.6.25-rc4/drivers/pci/hotplug/pci_hotplug_core.c
===================================================================
--- linux-2.6.25-rc4.orig/drivers/pci/hotplug/pci_hotplug_core.c
+++ linux-2.6.25-rc4/drivers/pci/hotplug/pci_hotplug_core.c
@@ -567,6 +567,11 @@ int pci_hp_register(struct hotplug_slot
return -EINVAL;
}
+ /*
+ * No problems if we call this interface from both ACPI_PCI_SLOT
+ * driver and call it here again. If we've already created the
+ * pci_slot, the interface will simply bump the refcount.
+ */
pci_slot = pci_create_slot(bus, slot_nr, slot->name);
if (IS_ERR(pci_slot))
return PTR_ERR(pci_slot);
@@ -613,8 +618,12 @@ int pci_hp_deregister(struct hotplug_slo
slot = hotplug->pci_slot;
fs_remove_slot(slot);
- pci_destroy_slot(slot);
dbg("Removed slot %s from the list\n", hotplug->name);
+
+ hotplug_release(slot);
+ slot->release = NULL;
+ pci_destroy_slot(slot);
+
return 0;
}
Index: linux-2.6.25-rc4/drivers/pci/hotplug/pciehp_core.c
===================================================================
--- linux-2.6.25-rc4.orig/drivers/pci/hotplug/pciehp_core.c
+++ linux-2.6.25-rc4/drivers/pci/hotplug/pciehp_core.c
@@ -249,7 +249,7 @@ static int init_slots(struct controller
if (retval == -EBUSY)
goto error_info;
if (retval) {
- err ("pci_hp_register failed with error %d\n", retval);
+ err("pci_hp_register failed with error %d\n", retval);
goto error_info;
}
/* create additional sysfs entries */
Index: linux-2.6.25-rc4/drivers/pci/hotplug/sgi_hotplug.c
===================================================================
--- linux-2.6.25-rc4.orig/drivers/pci/hotplug/sgi_hotplug.c
+++ linux-2.6.25-rc4/drivers/pci/hotplug/sgi_hotplug.c
@@ -668,7 +668,7 @@ static int sn_hotplug_slot_register(stru
register_err:
dev_dbg(&pci_bus->self->dev, "bus failed to register with err = %d\n",
- rc);
+ rc);
alloc_err:
if (rc == -ENOMEM)
next prev parent reply other threads:[~2008-03-11 13:25 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-02-29 0:23 [PATCH 0/4, v7] PCI, ACPI: Physical PCI slot objects Alex Chiang
2008-02-29 0:26 ` [PATCH 1/4] Remove path attribute from sgi_hotplug Alex Chiang
2008-03-03 18:48 ` Jesse Barnes
2008-03-03 18:54 ` Prarit Bhargava
2008-03-05 0:19 ` Alex Chiang
2008-02-29 0:27 ` [PATCH 2/4] Construct one fakephp slot per pci slot Alex Chiang
2008-02-29 0:28 ` [PATCH 3/4] Introduce pci_slot Alex Chiang
2008-03-01 5:24 ` Greg KH
2008-03-01 5:24 ` Greg KH
2008-03-03 20:56 ` Alex Chiang
2008-03-04 5:58 ` Greg KH
2008-03-04 5:58 ` Greg KH
2008-03-04 23:30 ` [PATCH 3/4, v8] " Alex Chiang
2008-02-29 0:29 ` [PATCH 4/4] ACPI PCI slot detection driver Alex Chiang
2008-03-01 5:25 ` Greg KH
2008-03-01 5:25 ` Greg KH
2008-03-01 14:43 ` Matthew Wilcox
2008-03-04 5:49 ` Greg KH
2008-03-04 18:18 ` Jesse Barnes
2008-03-04 19:30 ` Greg KH
2008-03-04 20:02 ` Jesse Barnes
2008-03-04 20:12 ` Kristen Carlson Accardi
2008-03-04 23:09 ` Alex Chiang
2008-03-05 1:11 ` Kenji Kaneshige
2008-03-05 1:11 ` Kenji Kaneshige
2008-03-05 20:20 ` Alex Chiang
2008-03-05 20:34 ` Matthew Wilcox
2008-03-05 20:34 ` Matthew Wilcox
2008-03-06 2:07 ` Kenji Kaneshige
2008-03-06 2:07 ` Kenji Kaneshige
2008-03-11 13:10 ` Kenji Kaneshige
2008-03-11 13:13 ` Kenji Kaneshige [this message]
2008-03-11 13:17 ` [PATCH 3/(3+1)] " Kenji Kaneshige
2008-03-11 13:19 ` [PATCH 4/(3+1)] Add quirks for " Kenji Kaneshige
2008-03-11 13:28 ` [PATCH 4/4] " Matthew Wilcox
2008-03-11 16:56 ` Jesse Barnes
2008-03-12 5:51 ` Kenji Kaneshige
2008-03-12 4:08 ` Kenji Kaneshige
2008-03-11 18:04 ` Kristen Carlson Accardi
2008-03-11 18:04 ` Kristen Carlson Accardi
2008-03-11 19:14 ` Alex Chiang
2008-03-12 11:33 ` Kenji Kaneshige
2008-03-12 11:33 ` Kenji Kaneshige
2008-03-13 3:24 ` Alex Chiang
2008-03-14 2:16 ` Gary Hade
2008-03-14 2:16 ` Gary Hade
2008-03-14 5:34 ` Kenji Kaneshige
2008-03-18 20:49 ` Alex Chiang
2008-03-12 10:50 ` Kenji Kaneshige
2008-03-12 10:50 ` Kenji Kaneshige
2008-03-11 23:34 ` Kristen Carlson Accardi
2008-03-11 23:34 ` Kristen Carlson Accardi
2008-03-12 12:59 ` Kenji Kaneshige
2008-03-04 22:58 ` Alex Chiang
2008-03-04 23:15 ` Greg KH
2008-03-04 23:15 ` Greg KH
2008-03-04 23:46 ` Alex Chiang
2008-03-01 5:12 ` [PATCH 0/4, v7] PCI, ACPI: Physical PCI slot objects Greg KH
2008-03-01 5:12 ` Greg KH
2008-03-03 23:35 ` Alex Chiang
2008-03-04 5:56 ` Greg KH
2008-03-04 5:56 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47D68580.6080207@jp.fujitsu.com \
--to=kaneshige.kenji@jp.fujitsu.com \
--cc=achiang@hp.com \
--cc=garyhade@us.ibm.com \
--cc=gregkh@suse.de \
--cc=jbarnes@virtuousgeek.org \
--cc=kristen.c.accardi@intel.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@atrey.karlin.mff.cuni.cz \
--cc=matthew@wil.cx \
--cc=rick.jones2@hp.com \
--cc=warthog19@eaglescrag.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.