[PATCH 4/4, v3] ACPI, PCI: ACPI PCI slot detection driver
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
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