[PATCH 4/4, v3] ACPI, PCI: ACPI PCI slot detection driver

2007-11-17 Thread Alex Chiang
Detect all physical PCI slots as described by ACPI, and create
entries in /sys/bus/pci/slots/.

Not all physical slots are hotpluggable, and the acpiphp module
does not detect them. Now we know the physical PCI geography of
our system, without caring about hotplug.

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 <[EMAIL PROTECTED]>
---
 drivers/acpi/Kconfig   |9 ++
 drivers/acpi/Makefile  |1 +
 drivers/acpi/pci_slot.c|  203 
 drivers/pci/hotplug/pci_hotplug_core.c |   15 +++
 4 files changed, 228 insertions(+), 0 deletions(-)
 create mode 100644 drivers/acpi/pci_slot.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 087a702..b1ce260 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -293,6 +293,15 @@ config ACPI_EC
  the battery and thermal drivers.  If you are compiling for a 
  mobile system, say Y.
 
+config ACPI_PCI_SLOT
+   bool "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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 54e3ab0..d89000e 100644
--- a/drivers/acpi/Makefile
+++ b/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
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
new file mode 100644
index 000..22f076b
--- /dev/null
+++ b/drivers/acpi/pci_slot.c
@@ -0,0 +1,203 @@
+/*
+ *  pci_slot.c - ACPI PCI Slot Driver
+ *
+ *  The code here is heavily leveraged from the acpiphp module.
+ *  Thanks to Matthew Wilcox <[EMAIL PROTECTED]> for much guidance.
+ *
+ *  Copyright (C) 2007 Alex Chiang <[EMAIL PROTECTED]>
+ *  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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#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)
+
+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,
+};
+
+/*
+ * register_slot - callback function to discover / create physical PCI slots
+ * @handle: any device underneath an acpi_pci_root (sometimes it's a slot
+ * device, sometimes not)
+ * @context: struct pci_bus
+ * The possible error conditions are non-fatal, so we always return
+ * AE_OK, as to not terminate our namespace walk prematurely.
+ */
+static acpi_status
+register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+   int device;
+   unsigned long adr, sun;
+   acpi_status status;
+   char name[KOBJ_NAME_LEN];
+
+   struct pci_slot *pci_slot;
+   struct pci_bus *pci_bus = context;
+
+   status = acpi_evaluate_integer(handle, "_ADR", NULL, );
+   if (ACPI_FAILURE(status))
+   return AE_OK;
+   device = (adr >> 16) & 0x;
+
+   /* No _SUN == not a slot == bail */
+   status = acpi_evaluate_integer(handle, "_SUN", NULL, );
+   

[PATCH 4/4, v3] ACPI, PCI: ACPI PCI slot detection driver

2007-11-17 Thread Alex Chiang
Detect all physical PCI slots as described by ACPI, and create
entries in /sys/bus/pci/slots/.

Not all physical slots are hotpluggable, and the acpiphp module
does not detect them. Now we know the physical PCI geography of
our system, without caring about hotplug.

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 [EMAIL PROTECTED]
---
 drivers/acpi/Kconfig   |9 ++
 drivers/acpi/Makefile  |1 +
 drivers/acpi/pci_slot.c|  203 
 drivers/pci/hotplug/pci_hotplug_core.c |   15 +++
 4 files changed, 228 insertions(+), 0 deletions(-)
 create mode 100644 drivers/acpi/pci_slot.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 087a702..b1ce260 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -293,6 +293,15 @@ config ACPI_EC
  the battery and thermal drivers.  If you are compiling for a 
  mobile system, say Y.
 
+config ACPI_PCI_SLOT
+   bool 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
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 54e3ab0..d89000e 100644
--- a/drivers/acpi/Makefile
+++ b/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
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
new file mode 100644
index 000..22f076b
--- /dev/null
+++ b/drivers/acpi/pci_slot.c
@@ -0,0 +1,203 @@
+/*
+ *  pci_slot.c - ACPI PCI Slot Driver
+ *
+ *  The code here is heavily leveraged from the acpiphp module.
+ *  Thanks to Matthew Wilcox [EMAIL PROTECTED] for much guidance.
+ *
+ *  Copyright (C) 2007 Alex Chiang [EMAIL PROTECTED]
+ *  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
+
+#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)
+
+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,
+};
+
+/*
+ * register_slot - callback function to discover / create physical PCI slots
+ * @handle: any device underneath an acpi_pci_root (sometimes it's a slot
+ * device, sometimes not)
+ * @context: struct pci_bus
+ * The possible error conditions are non-fatal, so we always return
+ * AE_OK, as to not terminate our namespace walk prematurely.
+ */
+static acpi_status
+register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+   int device;
+   unsigned long adr, sun;
+   acpi_status status;
+   char name[KOBJ_NAME_LEN];
+
+   struct pci_slot *pci_slot;
+   struct pci_bus *pci_bus = context;
+
+   status = acpi_evaluate_integer(handle, _ADR, NULL, adr);
+   if (ACPI_FAILURE(status))
+   return AE_OK;
+   device = (adr  16)  0x;
+
+   /* No _SUN == not