[PATCH 0/4, v3] Physical PCI slot objects - Kernel

This is a discussion on [PATCH 0/4, v3] Physical PCI slot objects - Kernel ; Hi all, This is v3 of the pci_slot patch series. The major change is making the ACPI-PCI slot driver a Kconfig option, as per the recommendations of others (Gary, Kenji-san). In the process of doing so, it made sense to ...

+ Reply to Thread
Page 1 of 2 1 2 LastLast
Results 1 to 20 of 34

Thread: [PATCH 0/4, v3] Physical PCI slot objects

  1. [PATCH 0/4, v3] Physical PCI slot objects

    Hi all,

    This is v3 of the pci_slot patch series.

    The major change is making the ACPI-PCI slot driver a Kconfig
    option, as per the recommendations of others (Gary, Kenji-san).
    In the process of doing so, it made sense to collapse the former
    3/5 and 4/5 patches into a single 3/4 patch. There really wasn't
    a reason to introduce a pci_slot patch, and then immediately
    follow it with another patch modifying its interface; logically,
    the changes should have been in the same patch.

    Combining the patches also has the nice side benefit of keeping
    the tree fully buildable and bisectable at all stages of series.

    I have done quite a bit more testing, and verified that this
    series plays nicely with acpiphp during all stages of the series.
    Notably, you can modprobe/rmmod acpiphp repeatedly no matter
    where you are in the series, and no matter whether you have
    CONFIG_ACPI_PCI_SLOT turned on. The correct entries in
    /sys/bus/pci/slots/ will appear and disappear, and we correctly
    register/deregister ACPI slots with the pci_hp core.

    Of course, if you *do* have the ACPI-PCI slot driver configured,
    the slots/ entries in sysfs will be persistent. What you will see
    is the hotplug attributes appear/disappear, depending on whether
    you have acpiphp loaded or not.

    Thanks for your consideration and all the feedback comments.
    They're appreciated.

    /ac

    v2 -> v3:
    Patch 1/4 - no change
    Patch 2/4 - incorporate Eike's comments around snprintf
    Patch 3/4 - Separated slot creation and slot hotplug ability
    into two interfaces. Fixed bugs in pci_destroy_slot(),
    and now properly calling from pci_hp_deregister.
    Patch 4/4 - 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:
    Patch 1/5 - reworked to fix stupid compile bug
    Patch 2/5 - incorporate Eike, Linas, and Willy's comments
    Patch 3/5 - no change
    Patch 4/5 - was acpi-pci-slot-driver patch, now modifies
    pci_add_hotplug(). I changed the ordering on this so
    the tree doesn't break at this point in the series
    Patch 5/5 - now is acpi-pci-slot-driver patch, cleaned up
    implementation so our slot detection is a little
    better
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  2. [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
    ---
    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 0000000..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 for much guidance.
    + *
    + * Copyright (C) 2007 Alex Chiang
    + * 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, &adr);
    + if (ACPI_FAILURE(status))
    + return AE_OK;
    + device = (adr >> 16) & 0xffff;
    +
    + /* No _SUN == not a slot == bail */
    + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
    + if (ACPI_FAILURE(status))
    + 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));
    + return AE_OK;
    + }
    +
    + return AE_OK;
    +}
    +
    +/*
    + * find_p2p_bridge - callback function to discover p2p bridges
    + */
    +static acpi_status
    +find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
    +{
    + int device, function;
    + unsigned long adr;
    + acpi_status status;
    + acpi_handle dummy_handle;
    +
    + struct pci_dev *dev;
    + struct pci_bus *pci_bus = context;
    +
    + 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;
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + register_slot, dev->subordinate, NULL);
    + if (ACPI_FAILURE(status))
    + goto out;
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + find_p2p_bridge, dev->subordinate, NULL);
    +out:
    + pci_dev_put(dev);
    + return AE_OK;
    +}
    +
    +#define ACPI_STA_FUNCTIONING (0x00000008)
    +
    +/*
    + * acpi_pci_slot_add - walk namespace under a PCI root bridge
    + * @handle: points to an acpi_pci_root
    + */
    +static int
    +acpi_pci_slot_add(acpi_handle handle)
    +{
    + int seg, bus;
    + unsigned long tmp;
    + acpi_status status;
    + acpi_handle dummy_handle;
    + struct pci_bus *pci_bus;
    +
    + /* 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;
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + register_slot, pci_bus, NULL);
    + if (ACPI_FAILURE(status)) {
    + err("%s: register_slot failure - %d\n", __FUNCTION__, status);
    + return status;
    + }
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + find_p2p_bridge, pci_bus, NULL);
    + if (ACPI_FAILURE(status))
    + err("%s: find_p2p_bridge failure - %d\n", __FUNCTION__, status);
    +
    + return status;
    +}
    +
    +static int __init
    +acpi_pci_slot_init(void)
    +{
    + acpi_pci_register_driver(&acpi_pci_slot_driver);
    + return 0;
    +}
    +
    +/*
    + * acpi_pci_slot_remove and acpi_pci_slot_exit are empty for now, since
    + * /sys/bus/pci/slots/ entries shouldn't ever really go away.
    + */
    +static void
    +acpi_pci_slot_remove(acpi_handle handle)
    +{
    +}
    +
    +static void __exit
    +acpi_pci_slot_exit(void)
    +{
    +}
    +
    +module_init(acpi_pci_slot_init);
    +module_exit(acpi_pci_slot_exit);
    diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
    index 1be5b0d..39bb5d3 100644
    --- a/drivers/pci/hotplug/pci_hotplug_core.c
    +++ b/drivers/pci/hotplug/pci_hotplug_core.c
    @@ -567,9 +567,15 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    return -EINVAL;
    }

    +#ifndef CONFIG_ACPI_PCI_SLOT
    + /*
    + * ACPI-PCI slot driver would have created the pci_slot for us,
    + * but we haven't configured it, so do it ourselves.
    + */
    pci_slot = pci_create_slot(bus, slot_nr, slot->name);
    if (IS_ERR(pci_slot))
    return PTR_ERR(pci_slot);
    +#endif

    pci_slot = pci_slot_add_hotplug(bus, slot_nr, hotplug_release);
    if (IS_ERR(pci_slot))
    @@ -610,7 +616,16 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)

    slot = hotplug->pci_slot;
    fs_remove_slot(slot);
    +#ifdef CONFIG_ACPI_PCI_SLOT
    + /*
    + * If we are using the ACPI-PCI slot driver, we don't want to
    + * destroy the pci_slot object. Rather, just release the
    + * hotplug_slot associated with it.
    + */
    + hotplug_release(slot);
    +#else
    pci_destroy_slot(slot);
    +#endif
    dbg("Removed slot %s from the list\n", hotplug->name);
    return 0;
    }
    --
    1.5.3.1.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  3. [PATCH 1/4, v3] PCI Hotplug: Remove path attribute from sgi_hotplug

    Rename the slot to be the contents of the 'path' sysfs attribute, and
    delete the attribute. The mapping from pci address to slot name is
    supposed to be done through the 'address' file, which will be provided
    automatically later in this series of patches.

    Signed-off-by: Alex Chiang
    Signed-off-by: Matthew Wilcox
    ---
    drivers/pci/hotplug/sgi_hotplug.c | 32 +-------------------------------
    1 files changed, 1 insertions(+), 31 deletions(-)

    diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
    index ef07c36..693519e 100644
    --- a/drivers/pci/hotplug/sgi_hotplug.c
    +++ b/drivers/pci/hotplug/sgi_hotplug.c
    @@ -91,21 +91,6 @@ static struct hotplug_slot_ops sn_hotplug_slot_ops = {

    static DEFINE_MUTEX(sn_hotplug_mutex);

    -static ssize_t path_show (struct hotplug_slot *bss_hotplug_slot,
    - char *buf)
    -{
    - int retval = -ENOENT;
    - struct slot *slot = bss_hotplug_slot->private;
    -
    - if (!slot)
    - return retval;
    -
    - retval = sprintf (buf, "%s\n", slot->physical_path);
    - return retval;
    -}
    -
    -static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
    -
    static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
    {
    struct pcibus_info *pcibus_info;
    @@ -173,18 +158,10 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
    return -ENOMEM;
    bss_hotplug_slot->private = slot;

    - bss_hotplug_slot->name = kmalloc(SN_SLOT_NAME_SIZE, GFP_KERNEL);
    - if (!bss_hotplug_slot->name) {
    - kfree(bss_hotplug_slot->private);
    - return -ENOMEM;
    - }
    + bss_hotplug_slot->name = slot->physical_path;

    slot->device_num = device;
    slot->pci_bus = pci_bus;
    - sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x",
    - pci_domain_nr(pci_bus),
    - ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
    - device + 1);

    sn_generate_path(pci_bus, slot->physical_path);

    @@ -203,8 +180,6 @@ static struct hotplug_slot * sn_hp_destroy(void)
    bss_hotplug_slot = slot->hotplug_slot;
    list_del(&((struct slot *)bss_hotplug_slot->private)->
    hp_list);
    - sysfs_remove_file(&bss_hotplug_slot->kobj,
    - &sn_slot_path_attr.attr);
    break;
    }
    return bss_hotplug_slot;
    @@ -653,11 +628,6 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
    rc = pci_hp_register(bss_hotplug_slot);
    if (rc)
    goto register_err;
    -
    - rc = sysfs_create_file(&bss_hotplug_slot->kobj,
    - &sn_slot_path_attr.attr);
    - if (rc)
    - goto register_err;
    }
    dev_dbg(&pci_bus->self->dev, "Registered bus with hotplug\n");
    return rc;
    --
    1.5.3.1.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  4. [PATCH 3/4, v3] PCI, PCI Hotplug: Introduce pci_slot

    - Make pci_slot the primary sysfs entity. hotplug_slot becomes a
    subsidiary structure.
    o pci_create_slot() creates and registers a slot with the PCI core
    o pci_slot_add_hotplug() gives it hotplug capability

    - Change the prototype of pci_hp_register() to take the bus and
    slot number (on parent bus) as parameters.

    - Remove all the ->get_address methods since this functionality is
    now handled by pci_slot directly.

    v2 -> v3:
    Separated slot creation and slot hotplug ability into two
    interfaces. Fixed bugs in pci_destroy_slot(), and now
    properly calling from pci_hp_deregister.

    v1 -> v2:
    No change

    Signed-off-by: Alex Chiang
    Signed-off-by: Matthew Wilcox
    ---
    drivers/pci/Makefile | 2 +-
    drivers/pci/hotplug/acpiphp.h | 1 -
    drivers/pci/hotplug/acpiphp_core.c | 23 +---
    drivers/pci/hotplug/acpiphp_glue.c | 16 --
    drivers/pci/hotplug/acpiphp_ibm.c | 5 +-
    drivers/pci/hotplug/cpci_hotplug_core.c | 2 +-
    drivers/pci/hotplug/cpqphp_core.c | 4 +-
    drivers/pci/hotplug/fakephp.c | 2 +-
    drivers/pci/hotplug/ibmphp_ebda.c | 3 +-
    drivers/pci/hotplug/pci_hotplug_core.c | 242 +++++++++++--------------------
    drivers/pci/hotplug/pciehp_core.c | 22 +--
    drivers/pci/hotplug/rpadlpar_sysfs.c | 4 +-
    drivers/pci/hotplug/sgi_hotplug.c | 2 +-
    drivers/pci/hotplug/shpchp_core.c | 17 +--
    drivers/pci/pci.h | 13 ++
    drivers/pci/slot.c | 184 +++++++++++++++++++++++
    include/linux/pci.h | 17 ++
    include/linux/pci_hotplug.h | 12 +-
    18 files changed, 328 insertions(+), 243 deletions(-)
    create mode 100644 drivers/pci/slot.c

    diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
    index 5550556..12f0b2d 100644
    --- a/drivers/pci/Makefile
    +++ b/drivers/pci/Makefile
    @@ -2,7 +2,7 @@
    # Makefile for the PCI bus specific drivers.
    #

    -obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
    +obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \
    pci-driver.o search.o pci-sysfs.o rom.o setup-res.o
    obj-$(CONFIG_PROC_FS) += proc.o

    diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
    index f6cc0c5..ab46189 100644
    --- a/drivers/pci/hotplug/acpiphp.h
    +++ b/drivers/pci/hotplug/acpiphp.h
    @@ -216,7 +216,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
    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);

    /* variables */
    extern int acpiphp_debug;
    diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
    index a0ca63a..34b8d0b 100644
    --- a/drivers/pci/hotplug/acpiphp_core.c
    +++ b/drivers/pci/hotplug/acpiphp_core.c
    @@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot);
    static int set_attention_status (struct hotplug_slot *slot, u8 value);
    static int get_power_status (struct hotplug_slot *slot, u8 *value);
    static int get_attention_status (struct hotplug_slot *slot, u8 *value);
    -static int get_address (struct hotplug_slot *slot, u32 *value);
    static int get_latch_status (struct hotplug_slot *slot, u8 *value);
    static int get_adapter_status (struct hotplug_slot *slot, u8 *value);

    @@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
    .get_attention_status = get_attention_status,
    .get_latch_status = get_latch_status,
    .get_adapter_status = get_adapter_status,
    - .get_address = get_address,
    };


    @@ -279,23 +277,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -
    -/**
    - * get_address - get pci address of a slot
    - * @hotplug_slot: slot to get status
    - * @value: pointer to struct pci_busdev (seg, bus, dev)
    - */
    -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = hotplug_slot->private;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = acpiphp_get_address(slot->acpi_slot);
    -
    - return 0;
    -}
    -
    static int __init init_acpi(void)
    {
    int retval;
    @@ -362,7 +343,9 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
    acpiphp_slot->slot = slot;
    snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun);

    - retval = pci_hp_register(slot->hotplug_slot);
    + retval = pci_hp_register(slot->hotplug_slot,
    + acpiphp_slot->bridge->pci_bus,
    + acpiphp_slot->device);
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_hpslot;
    diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
    index 1e125b5..02a2fd7 100644
    --- a/drivers/pci/hotplug/acpiphp_glue.c
    +++ b/drivers/pci/hotplug/acpiphp_glue.c
    @@ -1874,19 +1874,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)

    return (sta == 0) ? 0 : 1;
    }
    -
    -
    -/*
    - * pci address (seg/bus/dev)
    - */
    -u32 acpiphp_get_address(struct acpiphp_slot *slot)
    -{
    - u32 address;
    - struct pci_bus *pci_bus = slot->bridge->pci_bus;
    -
    - address = (pci_domain_nr(pci_bus) << 16) |
    - (pci_bus->number << 8) |
    - slot->device;
    -
    - return address;
    -}
    diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
    index 56829f8..927b1fb 100644
    --- a/drivers/pci/hotplug/acpiphp_ibm.c
    +++ b/drivers/pci/hotplug/acpiphp_ibm.c
    @@ -35,6 +35,7 @@
    #include

    #include "acpiphp.h"
    +extern struct kset pci_slots_subsys;

    #define DRIVER_VERSION "1.0.1"
    #define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery "
    @@ -428,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
    int retval = 0;
    acpi_status status;
    struct acpi_device *device;
    - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
    + struct kobject *sysdir = &pci_slots_subsys.kobj;

    dbg("%s\n", __FUNCTION__);

    @@ -475,7 +476,7 @@ init_return:
    static void __exit ibm_acpiphp_exit(void)
    {
    acpi_status status;
    - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
    + struct kobject *sysdir = &pci_slots_subsys.kobj;

    dbg("%s\n", __FUNCTION__);

    diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
    index ed4d44e..aa47b80 100644
    --- a/drivers/pci/hotplug/cpci_hotplug_core.c
    +++ b/drivers/pci/hotplug/cpci_hotplug_core.c
    @@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
    info->attention_status = cpci_get_attention_status(slot);

    dbg("registering slot %s", slot->hotplug_slot->name);
    - status = pci_hp_register(slot->hotplug_slot);
    + status = pci_hp_register(slot->hotplug_slot, bus, i);
    if (status) {
    err("pci_hp_register failed with error %d", status);
    goto error_name;
    diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
    index a96b739..67f6a0c 100644
    --- a/drivers/pci/hotplug/cpqphp_core.c
    +++ b/drivers/pci/hotplug/cpqphp_core.c
    @@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
    slot->bus, slot->device,
    slot->number, ctrl->slot_device_offset,
    slot_number);
    - result = pci_hp_register(hotplug_slot);
    + result = pci_hp_register(hotplug_slot,
    + ctrl->pci_dev->subordinate,
    + slot->device);
    if (result) {
    err("pci_hp_register failed with error %d\n", result);
    goto error_name;
    diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
    index 996c942..405c608 100644
    --- a/drivers/pci/hotplug/fakephp.c
    +++ b/drivers/pci/hotplug/fakephp.c
    @@ -120,7 +120,7 @@ static int add_slot(struct pci_dev *dev)
    slot->release = &dummy_release;
    slot->private = dslot;

    - retval = pci_hp_register(slot);
    + retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn));
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_dslot;
    diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
    index 600ed7b..eb7a1c0 100644
    --- a/drivers/pci/hotplug/ibmphp_ebda.c
    +++ b/drivers/pci/hotplug/ibmphp_ebda.c
    @@ -1000,7 +1000,8 @@ static int __init ebda_rsrc_controller (void)
    tmp_slot = list_entry (list, struct slot, ibm_slot_list);

    snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
    - pci_hp_register (tmp_slot->hotplug_slot);
    + pci_hp_register(tmp_slot->hotplug_slot,
    + pci_find_bus(0, tmp_slot->bus), tmp_slot->device);
    }

    print_ebda_hpc ();
    diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
    index 01c351c..1be5b0d 100644
    --- a/drivers/pci/hotplug/pci_hotplug_core.c
    +++ b/drivers/pci/hotplug/pci_hotplug_core.c
    @@ -40,6 +40,7 @@
    #include
    #include
    #include
    +#include "../pci.h"

    #define MY_NAME "pci_hotplug"

    @@ -61,43 +62,6 @@ static int debug;

    static LIST_HEAD(pci_hotplug_slot_list);

    -struct kset pci_hotplug_slots_subsys;
    -
    -static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
    - struct attribute *attr, char *buf)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
    - return attribute->show ? attribute->show(slot, buf) : -EIO;
    -}
    -
    -static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
    - struct attribute *attr, const char *buf, size_t len)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
    - return attribute->store ? attribute->store(slot, buf, len) : -EIO;
    -}
    -
    -static struct sysfs_ops hotplug_slot_sysfs_ops = {
    - .show = hotplug_slot_attr_show,
    - .store = hotplug_slot_attr_store,
    -};
    -
    -static void hotplug_slot_release(struct kobject *kobj)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - if (slot->release)
    - slot->release(slot);
    -}
    -
    -static struct kobj_type hotplug_slot_ktype = {
    - .sysfs_ops = &hotplug_slot_sysfs_ops,
    - .release = &hotplug_slot_release,
    -};
    -
    -decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
    -
    /* these strings match up with the values in pci_bus_speed */
    static char *pci_bus_speed_strings[] = {
    "33 MHz PCI", /* 0x00 */
    @@ -151,16 +115,15 @@ GET_STATUS(power_status, u8)
    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)

    -static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t power_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_power_status (slot, &value);
    + retval = get_power_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -168,9 +131,10 @@ exit:
    return retval;
    }

    -static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    unsigned long lpower;
    u8 power;
    int retval = 0;
    @@ -206,29 +170,30 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_power = {
    +static struct pci_slot_attribute hotplug_slot_attr_power = {
    .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .show = power_read_file,
    .store = power_write_file
    };

    -static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_attention_status (slot, &value);
    + retval = get_attention_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    - retval = sprintf (buf, "%d\n", value);
    + retval = sprintf(buf, "%d\n", value);

    exit:
    return retval;
    }

    -static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot_ops *ops = slot->hotplug->ops;
    unsigned long lattention;
    u8 attention;
    int retval = 0;
    @@ -237,13 +202,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
    attention = (u8)(lattention & 0xff);
    dbg (" - attention = %d\n", attention);

    - if (!try_module_get(slot->ops->owner)) {
    + if (!try_module_get(ops->owner)) {
    retval = -ENODEV;
    goto exit;
    }
    - if (slot->ops->set_attention_status)
    - retval = slot->ops->set_attention_status(slot, attention);
    - module_put(slot->ops->owner);
    + if (ops->set_attention_status)
    + retval = ops->set_attention_status(slot->hotplug, attention);
    + module_put(ops->owner);

    exit:
    if (retval)
    @@ -251,18 +216,18 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
    +static struct pci_slot_attribute hotplug_slot_attr_attention = {
    .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .show = attention_read_file,
    .store = attention_write_file
    };

    -static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_latch_status (slot, &value);
    + retval = get_latch_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -271,17 +236,17 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
    +static struct pci_slot_attribute hotplug_slot_attr_latch = {
    .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
    .show = latch_read_file,
    };

    -static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_adapter_status (slot, &value);
    + retval = get_adapter_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -290,42 +255,20 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
    +static struct pci_slot_attribute hotplug_slot_attr_presence = {
    .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
    .show = presence_read_file,
    };

    -static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
    -{
    - int retval;
    - u32 address;
    -
    - retval = get_address (slot, &address);
    - if (retval)
    - goto exit;
    - retval = sprintf (buf, "%04x:%02x:%02x\n",
    - (address >> 16) & 0xffff,
    - (address >> 8) & 0xff,
    - address & 0xff);
    -
    -exit:
    - return retval;
    -}
    -
    -static struct hotplug_slot_attribute hotplug_slot_attr_address = {
    - .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
    - .show = address_read_file,
    -};
    -
    static char *unknown_speed = "Unknown bus speed";

    -static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
    {
    char *speed_string;
    int retval;
    enum pci_bus_speed value;

    - retval = get_max_bus_speed (slot, &value);
    + retval = get_max_bus_speed(slot->hotplug, &value);
    if (retval)
    goto exit;

    @@ -340,18 +283,18 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
    +static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
    .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
    .show = max_bus_speed_read_file,
    };

    -static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
    {
    char *speed_string;
    int retval;
    enum pci_bus_speed value;

    - retval = get_cur_bus_speed (slot, &value);
    + retval = get_cur_bus_speed(slot->hotplug, &value);
    if (retval)
    goto exit;

    @@ -366,14 +309,15 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
    +static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
    .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
    .show = cur_bus_speed_read_file,
    };

    -static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    unsigned long ltest;
    u32 test;
    int retval = 0;
    @@ -396,13 +340,14 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_test = {
    +static struct pci_slot_attribute hotplug_slot_attr_test = {
    .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .store = test_write_file
    };

    -static int has_power_file (struct hotplug_slot *slot)
    +static int has_power_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if ((slot->ops->enable_slot) ||
    @@ -412,8 +357,9 @@ static int has_power_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_attention_file (struct hotplug_slot *slot)
    +static int has_attention_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if ((slot->ops->set_attention_status) ||
    @@ -422,8 +368,9 @@ static int has_attention_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_latch_file (struct hotplug_slot *slot)
    +static int has_latch_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_latch_status)
    @@ -431,8 +378,9 @@ static int has_latch_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_adapter_file (struct hotplug_slot *slot)
    +static int has_adapter_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_adapter_status)
    @@ -440,17 +388,9 @@ static int has_adapter_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_address_file (struct hotplug_slot *slot)
    -{
    - if ((!slot) || (!slot->ops))
    - return -ENODEV;
    - if (slot->ops->get_address)
    - return 0;
    - return -ENOENT;
    -}
    -
    -static int has_max_bus_speed_file (struct hotplug_slot *slot)
    +static int has_max_bus_speed_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_max_bus_speed)
    @@ -458,8 +398,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_cur_bus_speed_file (struct hotplug_slot *slot)
    +static int has_cur_bus_speed_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_cur_bus_speed)
    @@ -467,8 +408,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_test_file (struct hotplug_slot *slot)
    +static int has_test_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->hardware_test)
    @@ -476,7 +418,7 @@ static int has_test_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int fs_add_slot (struct hotplug_slot *slot)
    +static int fs_add_slot(struct pci_slot *slot)
    {
    int retval = 0;

    @@ -507,13 +449,6 @@ static int fs_add_slot (struct hotplug_slot *slot)
    goto exit_adapter;
    }

    - if (has_address_file(slot) == 0) {
    - retval = sysfs_create_file(&slot->kobj,
    - &hotplug_slot_attr_address.attr);
    - if (retval)
    - goto exit_address;
    - }
    -
    if (has_max_bus_speed_file(slot) == 0) {
    retval = sysfs_create_file(&slot->kobj,
    &hotplug_slot_attr_max_bus_speed.attr);
    @@ -546,10 +481,6 @@ exit_cur_speed:
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);

    exit_max_speed:
    - if (has_address_file(slot) == 0)
    - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
    -
    -exit_address:
    if (has_adapter_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);

    @@ -569,7 +500,7 @@ exit:
    return retval;
    }

    -static void fs_remove_slot (struct hotplug_slot *slot)
    +static void fs_remove_slot(struct pci_slot *slot)
    {
    if (has_power_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
    @@ -583,9 +514,6 @@ static void fs_remove_slot (struct hotplug_slot *slot)
    if (has_adapter_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);

    - if (has_address_file(slot) == 0)
    - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
    -
    if (has_max_bus_speed_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);

    @@ -609,6 +537,12 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
    return NULL;
    }

    +static void hotplug_release(struct pci_slot *slot)
    +{
    + struct hotplug_slot *hotplug = slot->hotplug;
    + hotplug->release(hotplug);
    +}
    +
    /**
    * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
    * @slot: pointer to the &struct hotplug_slot to register
    @@ -618,8 +552,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int pci_hp_register (struct hotplug_slot *slot)
    +int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    {
    + struct pci_slot *pci_slot;
    int result;

    if (slot == NULL)
    @@ -632,18 +567,20 @@ int pci_hp_register (struct hotplug_slot *slot)
    return -EINVAL;
    }

    - kobject_set_name(&slot->kobj, "%s", slot->name);
    - kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
    + pci_slot = pci_create_slot(bus, slot_nr, slot->name);
    + if (IS_ERR(pci_slot))
    + return PTR_ERR(pci_slot);

    - /* this can fail if we have already registered a slot with the same name */
    - if (kobject_register(&slot->kobj)) {
    - err("Unable to register kobject");
    - return -EINVAL;
    - }
    -
    - list_add (&slot->slot_list, &pci_hotplug_slot_list);
    + pci_slot = pci_slot_add_hotplug(bus, slot_nr, hotplug_release);
    + if (IS_ERR(pci_slot))
    + return PTR_ERR(pci_slot);
    +
    + slot->pci_slot = pci_slot;
    + pci_slot->hotplug = slot;

    - result = fs_add_slot (slot);
    + list_add(&slot->slot_list, &pci_hotplug_slot_list);
    +
    + result = fs_add_slot(pci_slot);
    dbg ("Added slot %s to the list\n", slot->name);
    return result;
    }
    @@ -657,22 +594,24 @@ int pci_hp_register (struct hotplug_slot *slot)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int pci_hp_deregister (struct hotplug_slot *slot)
    +int pci_hp_deregister(struct hotplug_slot *hotplug)
    {
    struct hotplug_slot *temp;
    + struct pci_slot *slot;

    - if (slot == NULL)
    + if (!hotplug)
    return -ENODEV;

    - temp = get_slot_from_name (slot->name);
    - if (temp != slot) {
    + temp = get_slot_from_name(hotplug->name);
    + if (temp != hotplug)
    return -ENODEV;
    - }
    - list_del (&slot->slot_list);

    - fs_remove_slot (slot);
    - dbg ("Removed slot %s from the list\n", slot->name);
    - kobject_unregister(&slot->kobj);
    + list_del(&hotplug->slot_list);
    +
    + slot = hotplug->pci_slot;
    + fs_remove_slot(slot);
    + pci_destroy_slot(slot);
    + dbg("Removed slot %s from the list\n", hotplug->name);
    return 0;
    }

    @@ -686,13 +625,15 @@ int pci_hp_deregister (struct hotplug_slot *slot)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
    +int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
    struct hotplug_slot_info *info)
    {
    - if ((slot == NULL) || (info == NULL))
    + struct pci_slot *slot;
    + if (!hotplug || !info)
    return -ENODEV;
    + slot = hotplug->pci_slot;

    - memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
    + memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));

    return 0;
    }
    @@ -701,31 +642,21 @@ static int __init pci_hotplug_init (void)
    {
    int result;

    - kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
    - result = subsystem_register(&pci_hotplug_slots_subsys);
    - if (result) {
    - err("Register subsys with error %d\n", result);
    - goto exit;
    - }
    result = cpci_hotplug_init(debug);
    if (result) {
    err ("cpci_hotplug_init with error %d\n", result);
    - goto err_subsys;
    + goto err_cpci;
    }

    info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
    - goto exit;
    -
    -err_subsys:
    - subsystem_unregister(&pci_hotplug_slots_subsys);
    -exit:
    +
    +err_cpci:
    return result;
    }

    static void __exit pci_hotplug_exit (void)
    {
    cpci_hotplug_exit();
    - subsystem_unregister(&pci_hotplug_slots_subsys);
    }

    module_init(pci_hotplug_init);
    @@ -737,7 +668,6 @@ MODULE_LICENSE("GPL");
    module_param(debug, bool, 0644);
    MODULE_PARM_DESC(debug, "Debugging mode enabled or not");

    -EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
    EXPORT_SYMBOL_GPL(pci_hp_register);
    EXPORT_SYMBOL_GPL(pci_hp_deregister);
    EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
    diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
    index 6462ac3..8fee402 100644
    --- a/drivers/pci/hotplug/pciehp_core.c
    +++ b/drivers/pci/hotplug/pciehp_core.c
    @@ -69,7 +69,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
    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 *slot, enum pci_bus_speed *value);
    static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);

    @@ -82,7 +81,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
    .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,
    };
    @@ -245,14 +243,16 @@ static int init_slots(struct controller *ctrl)
    dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
    "slot_device_offset=%x\n", slot->bus, slot->device,
    slot->hp_slot, slot->number, ctrl->slot_device_offset);
    - retval = pci_hp_register(hotplug_slot);
    + retval = pci_hp_register(hotplug_slot,
    + ctrl->pci_dev->subordinate,
    + slot->number);
    if (retval) {
    err ("pci_hp_register failed with error %d\n", retval);
    goto error_info;
    }
    /* create additional sysfs entries */
    if (EMI(ctrl->ctrlcap)) {
    - retval = sysfs_create_file(&hotplug_slot->kobj,
    + retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
    &hotplug_slot_attr_lock.attr);
    if (retval) {
    pci_hp_deregister(hotplug_slot);
    @@ -285,7 +285,7 @@ static void cleanup_slots(struct controller *ctrl)
    slot = list_entry(tmp, struct slot, slot_list);
    list_del(&slot->slot_list);
    if (EMI(ctrl->ctrlcap))
    - sysfs_remove_file(&slot->hotplug_slot->kobj,
    + sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
    &hotplug_slot_attr_lock.attr);
    cancel_delayed_work(&slot->work);
    flush_scheduled_work();
    @@ -387,18 +387,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = hotplug_slot->private;
    - struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
    -
    - return 0;
    -}
    -
    static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
    {
    struct slot *slot = hotplug_slot->private;
    diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
    index a080fed..3663507 100644
    --- a/drivers/pci/hotplug/rpadlpar_sysfs.c
    +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
    @@ -23,6 +23,8 @@

    #define MAX_DRC_NAME_LEN 64

    +extern struct kset pci_slots_subsys;
    +
    /* Store return code of dlpar operation in attribute struct */
    struct dlpar_io_attr {
    int rc;
    @@ -130,7 +132,7 @@ struct kobj_type ktype_dlpar_io = {

    struct kset dlpar_io_kset = {
    .kobj = {.ktype = &ktype_dlpar_io,
    - .parent = &pci_hotplug_slots_subsys.kobj},
    + .parent = &pci_slots_subsys.kobj},
    .ktype = &ktype_dlpar_io,
    };

    diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
    index 693519e..cc74602 100644
    --- a/drivers/pci/hotplug/sgi_hotplug.c
    +++ b/drivers/pci/hotplug/sgi_hotplug.c
    @@ -625,7 +625,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
    bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
    bss_hotplug_slot->release = &sn_release_slot;

    - rc = pci_hp_register(bss_hotplug_slot);
    + rc = pci_hp_register(bss_hotplug_slot, pci_bus, device);
    if (rc)
    goto register_err;
    }
    diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
    index 80dec97..22c4d2e 100644
    --- a/drivers/pci/hotplug/shpchp_core.c
    +++ b/drivers/pci/hotplug/shpchp_core.c
    @@ -65,7 +65,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
    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 *slot, enum pci_bus_speed *value);
    static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);

    @@ -78,7 +77,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
    .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,
    };
    @@ -152,7 +150,8 @@ static int init_slots(struct controller *ctrl)
    dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
    "slot_device_offset=%x\n", slot->bus, slot->device,
    slot->hp_slot, slot->number, ctrl->slot_device_offset);
    - retval = pci_hp_register(slot->hotplug_slot);
    + retval = pci_hp_register(slot->hotplug_slot,
    + ctrl->pci_dev->subordinate, slot->device);
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_info;
    @@ -277,18 +276,6 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = get_slot(hotplug_slot);
    - struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
    -
    - return 0;
    -}
    -
    static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
    {
    struct slot *slot = get_slot(hotplug_slot);
    diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
    index fc87e14..4bcfabf 100644
    --- a/drivers/pci/pci.h
    +++ b/drivers/pci/pci.h
    @@ -91,3 +91,16 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
    }

    struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
    +
    +/* PCI slot sysfs helper code */
    +#define to_pci_slot(s) container_of(s, struct pci_slot, kobj)
    +
    +extern struct kset pci_slots_subsys;
    +
    +struct pci_slot_attribute {
    + struct attribute attr;
    + ssize_t (*show)(struct pci_slot *, char *);
    + ssize_t (*store)(struct pci_slot *, const char *, size_t);
    +};
    +#define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
    +
    diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
    new file mode 100644
    index 0000000..f4ca61b
    --- /dev/null
    +++ b/drivers/pci/slot.c
    @@ -0,0 +1,184 @@
    +/*
    + * drivers/pci/slot.c
    + * Copyright (c) 2006 Matthew Wilcox
    + * Copyright (c) 2006 Hewlett-Packard Company
    + */
    +
    +#include
    +#include
    +#include "pci.h"
    +
    +struct kset pci_slots_subsys;
    +EXPORT_SYMBOL_GPL(pci_slots_subsys);
    +
    +static ssize_t pci_slot_attr_show(struct kobject *kobj,
    + struct attribute *attr, char *buf)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
    + return attribute->show ? attribute->show(slot, buf) : -EIO;
    +}
    +
    +static ssize_t pci_slot_attr_store(struct kobject *kobj,
    + struct attribute *attr, const char *buf, size_t len)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
    + return attribute->store ? attribute->store(slot, buf, len) : -EIO;
    +}
    +
    +static struct sysfs_ops pci_slot_sysfs_ops = {
    + .show = pci_slot_attr_show,
    + .store = pci_slot_attr_store,
    +};
    +
    +static void pci_slot_release(struct kobject *kobj)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + slot->release(slot);
    + kfree(slot);
    +}
    +
    +static struct kobj_type pci_slot_ktype = {
    + .sysfs_ops = &pci_slot_sysfs_ops,
    + .release = &pci_slot_release,
    +};
    +
    +decl_subsys_name(pci_slots, slots, &pci_slot_ktype, NULL);
    +
    +static ssize_t address_read_file(struct pci_slot *slot, char *buf)
    +{
    + return sprintf(buf, "%04x:%02x:%02x\n", pci_domain_nr(slot->bus),
    + slot->bus->number, slot->number);
    +}
    +
    +static struct pci_slot_attribute pci_slot_attr_address = {
    + .attr = { .name = "address", .mode = S_IFREG | S_IRUGO },
    + .show = address_read_file,
    +};
    +
    +static void remove_sysfs_files(struct pci_slot *slot)
    +{
    + sysfs_remove_file(&slot->kobj, &pci_slot_attr_address.attr);
    +}
    +
    +static int create_sysfs_files(struct pci_slot *slot)
    +{
    + int result;
    +
    + result = sysfs_create_file(&slot->kobj, &pci_slot_attr_address.attr);
    +
    + return result;
    +}
    +
    +struct pci_slot *pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    + void (*release)(struct pci_slot *))
    +{
    + struct pci_slot *slot;
    + int found = 0;
    +
    + down_write(&pci_bus_sem);
    +
    + /* This slot should have already been created, so look for it. If
    + * we can't find it, return -EEXIST.
    + */
    + for (slot = parent->slot; slot; slot = slot->next)
    + if (slot->number == slot_nr) {
    + found = 1;
    + break;
    + }
    +
    + if (!found) {
    + slot = ERR_PTR(-EEXIST);
    + goto out;
    + }
    +
    + slot->release = release;
    + out:
    + up_write(&pci_bus_sem);
    + return slot;
    +}
    +EXPORT_SYMBOL_GPL(pci_slot_add_hotplug);
    +
    +struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
    + const char *name)
    +{
    + struct pci_slot *slot;
    + int err;
    +
    + down_write(&pci_bus_sem);
    +
    + /* If we've already created this slot, just return. */
    + for (slot = parent->slot; slot; slot = slot->next) {
    + if (slot->number != slot_nr)
    + continue;
    + goto out;
    + }
    +
    + slot = kzalloc(sizeof(*slot), GFP_KERNEL);
    + if (!slot) {
    + slot = ERR_PTR(-ENOMEM);
    + goto out;
    + }
    +
    + slot->bus = parent;
    + slot->number = slot_nr;
    +
    + kobject_set_name(&slot->kobj, "%s", name);
    + kobj_set_kset_s(slot, pci_slots_subsys);
    + if (kobject_register(&slot->kobj)) {
    + printk(KERN_ERR "Unable to register kobject %s", name);
    + err = -EINVAL;
    + goto err;
    + }
    +
    + err = create_sysfs_files(slot);
    + if (err)
    + goto unregister;
    +
    + slot->next = parent->slot;
    + parent->slot = slot;
    +
    + out:
    + up_write(&pci_bus_sem);
    + return slot;
    +
    + unregister:
    + kobject_unregister(&slot->kobj);
    + err:
    + kfree(slot);
    + slot = ERR_PTR(err);
    + goto out;
    +}
    +EXPORT_SYMBOL_GPL(pci_create_slot);
    +
    +int pci_destroy_slot(struct pci_slot *slot)
    +{
    + struct pci_slot **pprev;
    +
    + for (pprev = &slot->bus->slot; *pprev; pprev = &(*pprev)->next) {
    + if (*pprev == slot) {
    + *pprev = slot->next;
    + break;
    + }
    + }
    +
    + remove_sysfs_files(slot);
    + kobject_unregister(&slot->kobj);
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(pci_destroy_slot);
    +
    +static int pci_slot_init(void)
    +{
    + int result;
    +
    + kobj_set_kset_s(&pci_slots_subsys, pci_bus_type.subsys);
    + result = subsystem_register(&pci_slots_subsys);
    + if (result)
    + printk(KERN_ERR "PCI: Slot initialisation failure (%d)",
    + result);
    + return result;
    +}
    +
    +subsys_initcall(pci_slot_init);
    diff --git a/include/linux/pci.h b/include/linux/pci.h
    index 0dd93bb..ae2245f 100644
    --- a/include/linux/pci.h
    +++ b/include/linux/pci.h
    @@ -129,6 +129,16 @@ struct pci_cap_saved_state {
    u32 data[0];
    };

    +/* pci_slot represents a physical slot */
    +struct pci_slot {
    + struct pci_bus *bus; /* The bus this slot is on */
    + struct pci_slot *next; /* Next slot on this bus */
    + struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */
    + unsigned char number; /* PCI_SLOT(pci_dev->devfn) */
    + struct kobject kobj;
    + void (*release)(struct pci_slot *);
    +};
    +
    /*
    * The pci_dev structure is used to describe PCI devices.
    */
    @@ -140,6 +150,7 @@ struct pci_dev {

    void *sysdata; /* hook for sys-specific extension */
    struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
    + struct pci_slot *slot; /* Physical slot this device is in */

    unsigned int devfn; /* encoded device & function index */
    unsigned short vendor;
    @@ -261,6 +272,7 @@ struct pci_bus {
    struct list_head children; /* list of child buses */
    struct list_head devices; /* list of devices on this bus */
    struct pci_dev *self; /* bridge device as seen by parent */
    + struct pci_slot *slot; /* First physical slot on this bus */
    struct resource *resource[PCI_BUS_NUM_RESOURCES];
    /* address space routed to this bus */

    @@ -470,6 +482,11 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s
    }
    struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
    struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
    +struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
    + const char *name);
    +struct pci_slot *pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    + void (*release)(struct pci_slot *));
    +int pci_destroy_slot(struct pci_slot *slot);
    int pci_scan_slot(struct pci_bus *bus, int devfn);
    struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
    void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
    diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
    index ab4cb6e..bb36c59 100644
    --- a/include/linux/pci_hotplug.h
    +++ b/include/linux/pci_hotplug.h
    @@ -95,9 +95,6 @@ struct hotplug_slot_attribute {
    * @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.
    @@ -120,7 +117,6 @@ struct hotplug_slot_ops {
    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);
    };
    @@ -140,7 +136,6 @@ struct hotplug_slot_info {
    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;
    };
    @@ -166,15 +161,14 @@ struct hotplug_slot {

    /* Variables below this are for use only by the hotplug pci core. */
    struct list_head slot_list;
    - struct kobject kobj;
    + struct pci_slot *pci_slot;
    };
    #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)

    -extern int pci_hp_register (struct hotplug_slot *slot);
    -extern int pci_hp_deregister (struct hotplug_slot *slot);
    +extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr);
    +extern int pci_hp_deregister(struct hotplug_slot *slot);
    extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
    struct hotplug_slot_info *info);
    -extern struct kset pci_hotplug_slots_subsys;

    /* PCI Setting Record (Type 0) */
    struct hpp_type0 {
    --
    1.5.3.1.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  5. [PATCH 2/4, v3] PCI Hotplug: Construct one fakephp slot per pci slot

    Register one slot per slot, rather than one slot per function.
    Change the name of the slot to fake%d instead of the pci address.

    Signed-off-by: Alex Chiang
    Signed-off-by: Matthew Wilcox
    ---
    drivers/pci/hotplug/fakephp.c | 80 +++++++++++++++-------------------------
    1 files changed, 30 insertions(+), 50 deletions(-)

    diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
    index 027f686..996c942 100644
    --- a/drivers/pci/hotplug/fakephp.c
    +++ b/drivers/pci/hotplug/fakephp.c
    @@ -63,6 +63,7 @@ struct dummy_slot {
    struct list_head node;
    struct hotplug_slot *slot;
    struct pci_dev *dev;
    + char name[8];
    };

    static int debug;
    @@ -93,6 +94,7 @@ static int add_slot(struct pci_dev *dev)
    struct dummy_slot *dslot;
    struct hotplug_slot *slot;
    int retval = -ENOMEM;
    + static int count = 1;

    slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
    if (!slot)
    @@ -106,13 +108,14 @@ static int add_slot(struct pci_dev *dev)
    slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
    slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;

    - slot->name = &dev->dev.bus_id[0];
    - dbg("slot->name = %s\n", slot->name);
    -
    dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
    if (!dslot)
    goto error_info;

    + slot->name = dslot->name;
    + snprintf(slot->name, sizeof(dslot->name), "fake%d", count++);
    + dbg("slot->name = %s\n", slot->name);
    +
    slot->ops = &dummy_hotplug_slot_ops;
    slot->release = &dummy_release;
    slot->private = dslot;
    @@ -141,17 +144,17 @@ error:
    static int __init pci_scan_buses(void)
    {
    struct pci_dev *dev = NULL;
    - int retval = 0;
    + int lastslot = 0;

    while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
    - retval = add_slot(dev);
    - if (retval) {
    - pci_dev_put(dev);
    - break;
    - }
    + if (PCI_FUNC(dev->devfn) > 0 &&
    + lastslot == PCI_SLOT(dev->devfn))
    + continue;
    + lastslot = PCI_SLOT(dev->devfn);
    + add_slot(dev);
    }

    - return retval;
    + return 0;
    }

    static void remove_slot(struct dummy_slot *dslot)
    @@ -275,23 +278,9 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
    return -ENODEV;
    }

    -/* find the hotplug_slot for the pci_dev */
    -static struct hotplug_slot *get_slot_from_dev(struct pci_dev *dev)
    -{
    - struct dummy_slot *dslot;
    -
    - list_for_each_entry(dslot, &slot_list, node) {
    - if (dslot->dev == dev)
    - return dslot->slot;
    - }
    - return NULL;
    -}
    -
    -
    static int disable_slot(struct hotplug_slot *slot)
    {
    struct dummy_slot *dslot;
    - struct hotplug_slot *hslot;
    struct pci_dev *dev;
    int func;

    @@ -301,36 +290,27 @@ static int disable_slot(struct hotplug_slot *slot)

    dbg("%s - physical_slot = %s\n", __FUNCTION__, slot->name);

    - /* don't disable bridged devices just yet, we can't handle them easily... */
    - if (dslot->dev->subordinate) {
    - err("Can't remove PCI devices with other PCI devices behind it yet.\n");
    - return -ENODEV;
    - }
    - /* search for subfunctions and disable them first */
    - if (!(dslot->dev->devfn & 7)) {
    - for (func = 1; func < 8; func++) {
    - dev = pci_get_slot(dslot->dev->bus,
    - dslot->dev->devfn + func);
    - if (dev) {
    - hslot = get_slot_from_dev(dev);
    - if (hslot)
    - disable_slot(hslot);
    - else {
    - err("Hotplug slot not found for subfunction of PCI device\n");
    - return -ENODEV;
    - }
    - pci_dev_put(dev);
    - } else
    - dbg("No device in slot found\n");
    + for (func = 7; func >= 0; func--) {
    + dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func);
    + if (!dev)
    + continue;
    +
    + /* don't disable bridged devices just yet, we can't handle
    + * them easily... */
    + if (dev->subordinate) {
    + err("Can't remove PCI devices with other PCI devices behind it yet.\n");
    + return -ENODEV;
    }
    - }

    - /* remove the device from the pci core */
    - pci_remove_bus_device(dslot->dev);

    - /* blow away this sysfs entry and other parts. */
    - remove_slot(dslot);
    + /* remove the device from the pci core */
    + pci_remove_bus_device(dslot->dev);

    + /* blow away this sysfs entry and other parts. */
    + remove_slot(dslot);
    +
    + pci_dev_put(dev);
    + }
    return 0;
    }

    --
    1.5.3.1.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  6. Re: [PATCH 0/4, v3] Physical PCI slot objects

    On Sat, 17 Nov 2007 11:29:54 -0700
    Alex Chiang wrote:

    > I have done quite a bit more testing, and verified that this
    > series plays nicely with acpiphp during all stages of the series.
    > Notably, you can modprobe/rmmod acpiphp repeatedly no matter
    > where you are in the series, and no matter whether you have
    > CONFIG_ACPI_PCI_SLOT turned on. The correct entries in
    > /sys/bus/pci/slots/ will appear and disappear, and we correctly
    > register/deregister ACPI slots with the pci_hp core.


    Hi Alex,
    How does this patch play with non-acpi based hotplug such as the pciehp
    driver or the shpchp driver for example?

    Thanks,
    Kristen
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  7. Re: [PATCH 0/4, v3] Physical PCI slot objects

    * Kristen Carlson Accardi :
    > On Sat, 17 Nov 2007 11:29:54 -0700
    > Alex Chiang wrote:
    >
    > > I have done quite a bit more testing, and verified that this
    > > series plays nicely with acpiphp during all stages of the series.
    > > Notably, you can modprobe/rmmod acpiphp repeatedly no matter
    > > where you are in the series, and no matter whether you have
    > > CONFIG_ACPI_PCI_SLOT turned on. The correct entries in
    > > /sys/bus/pci/slots/ will appear and disappear, and we correctly
    > > register/deregister ACPI slots with the pci_hp core.

    >
    > How does this patch play with non-acpi based hotplug such as the pciehp
    > driver


    Not well.

    pciehp: HPC vendor_id 103c device_id 403b ss_vid 0 ss_did 0
    pciehp: pci_hp_register failed with error -17
    pciehp: pciehp: slot initialization failed
    pciehp: HPC vendor_id 111d device_id 801c ss_vid 0 ss_did 0
    pciehp: Can't get irq 0 for the hotplug controller
    pciehp: HPC vendor_id 111d device_id 801c ss_vid 0 ss_did 0
    pciehp: Can't get irq 0 for the hotplug controller
    pciehp: HPC vendor_id 103c device_id 403b ss_vid 0 ss_did 0
    pciehp: pci_hp_register failed with error -17
    pciehp: pciehp: slot initialization failed

    I'll take a look at this today. Thanks for pointing it out.

    > or the shpchp driver for example?


    This one, I'm not sure on, as I don't have any shpc hardware.
    I'll do my best by just looking at the code, but maybe if someone
    out there has that hardware, they could let me know what breaks?

    Thanks.

    /ac

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  8. [PATCH 3/4, v4] PCI, PCI Hotplug: Introduce pci_slot

    - Make pci_slot the primary sysfs entity. hotplug_slot becomes a
    subsidiary structure.
    o pci_create_slot() creates and registers a slot with the PCI core
    o pci_slot_add_hotplug() gives it hotplug capability

    - Change the prototype of pci_hp_register() to take the bus and
    slot number (on parent bus) as parameters.

    - Remove all the ->get_address methods since this functionality is
    now handled by pci_slot directly.

    v3 -> v4:
    Fixed bug with pciehp and rpaphp registering slots

    v2 -> v3:
    Separated slot creation and slot hotplug ability into two
    interfaces. Fixed bugs in pci_destroy_slot(), and now
    properly calling from pci_hp_deregister.

    v1 -> v2:
    No change

    Signed-off-by: Alex Chiang
    Signed-off-by: Matthew Wilcox
    ---
    drivers/pci/Makefile | 2 +-
    drivers/pci/hotplug/acpiphp.h | 1 -
    drivers/pci/hotplug/acpiphp_core.c | 23 +---
    drivers/pci/hotplug/acpiphp_glue.c | 16 --
    drivers/pci/hotplug/acpiphp_ibm.c | 5 +-
    drivers/pci/hotplug/cpci_hotplug_core.c | 2 +-
    drivers/pci/hotplug/cpqphp_core.c | 4 +-
    drivers/pci/hotplug/fakephp.c | 2 +-
    drivers/pci/hotplug/ibmphp_ebda.c | 3 +-
    drivers/pci/hotplug/pci_hotplug_core.c | 242 +++++++++++--------------------
    drivers/pci/hotplug/pciehp_core.c | 22 +--
    drivers/pci/hotplug/rpadlpar_sysfs.c | 4 +-
    drivers/pci/hotplug/rpaphp_slot.c | 3 +-
    drivers/pci/hotplug/sgi_hotplug.c | 2 +-
    drivers/pci/hotplug/shpchp_core.c | 17 +--
    drivers/pci/pci.h | 13 ++
    drivers/pci/slot.c | 184 +++++++++++++++++++++++
    include/linux/pci.h | 17 ++
    include/linux/pci_hotplug.h | 12 +-
    19 files changed, 330 insertions(+), 244 deletions(-)
    create mode 100644 drivers/pci/slot.c

    diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
    index 5550556..12f0b2d 100644
    --- a/drivers/pci/Makefile
    +++ b/drivers/pci/Makefile
    @@ -2,7 +2,7 @@
    # Makefile for the PCI bus specific drivers.
    #

    -obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
    +obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \
    pci-driver.o search.o pci-sysfs.o rom.o setup-res.o
    obj-$(CONFIG_PROC_FS) += proc.o

    diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
    index f6cc0c5..ab46189 100644
    --- a/drivers/pci/hotplug/acpiphp.h
    +++ b/drivers/pci/hotplug/acpiphp.h
    @@ -216,7 +216,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
    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);

    /* variables */
    extern int acpiphp_debug;
    diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
    index a0ca63a..34b8d0b 100644
    --- a/drivers/pci/hotplug/acpiphp_core.c
    +++ b/drivers/pci/hotplug/acpiphp_core.c
    @@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot);
    static int set_attention_status (struct hotplug_slot *slot, u8 value);
    static int get_power_status (struct hotplug_slot *slot, u8 *value);
    static int get_attention_status (struct hotplug_slot *slot, u8 *value);
    -static int get_address (struct hotplug_slot *slot, u32 *value);
    static int get_latch_status (struct hotplug_slot *slot, u8 *value);
    static int get_adapter_status (struct hotplug_slot *slot, u8 *value);

    @@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
    .get_attention_status = get_attention_status,
    .get_latch_status = get_latch_status,
    .get_adapter_status = get_adapter_status,
    - .get_address = get_address,
    };


    @@ -279,23 +277,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -
    -/**
    - * get_address - get pci address of a slot
    - * @hotplug_slot: slot to get status
    - * @value: pointer to struct pci_busdev (seg, bus, dev)
    - */
    -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = hotplug_slot->private;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = acpiphp_get_address(slot->acpi_slot);
    -
    - return 0;
    -}
    -
    static int __init init_acpi(void)
    {
    int retval;
    @@ -362,7 +343,9 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
    acpiphp_slot->slot = slot;
    snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun);

    - retval = pci_hp_register(slot->hotplug_slot);
    + retval = pci_hp_register(slot->hotplug_slot,
    + acpiphp_slot->bridge->pci_bus,
    + acpiphp_slot->device);
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_hpslot;
    diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
    index 1e125b5..02a2fd7 100644
    --- a/drivers/pci/hotplug/acpiphp_glue.c
    +++ b/drivers/pci/hotplug/acpiphp_glue.c
    @@ -1874,19 +1874,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)

    return (sta == 0) ? 0 : 1;
    }
    -
    -
    -/*
    - * pci address (seg/bus/dev)
    - */
    -u32 acpiphp_get_address(struct acpiphp_slot *slot)
    -{
    - u32 address;
    - struct pci_bus *pci_bus = slot->bridge->pci_bus;
    -
    - address = (pci_domain_nr(pci_bus) << 16) |
    - (pci_bus->number << 8) |
    - slot->device;
    -
    - return address;
    -}
    diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
    index 56829f8..927b1fb 100644
    --- a/drivers/pci/hotplug/acpiphp_ibm.c
    +++ b/drivers/pci/hotplug/acpiphp_ibm.c
    @@ -35,6 +35,7 @@
    #include

    #include "acpiphp.h"
    +extern struct kset pci_slots_subsys;

    #define DRIVER_VERSION "1.0.1"
    #define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery "
    @@ -428,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
    int retval = 0;
    acpi_status status;
    struct acpi_device *device;
    - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
    + struct kobject *sysdir = &pci_slots_subsys.kobj;

    dbg("%s\n", __FUNCTION__);

    @@ -475,7 +476,7 @@ init_return:
    static void __exit ibm_acpiphp_exit(void)
    {
    acpi_status status;
    - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
    + struct kobject *sysdir = &pci_slots_subsys.kobj;

    dbg("%s\n", __FUNCTION__);

    diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
    index ed4d44e..aa47b80 100644
    --- a/drivers/pci/hotplug/cpci_hotplug_core.c
    +++ b/drivers/pci/hotplug/cpci_hotplug_core.c
    @@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
    info->attention_status = cpci_get_attention_status(slot);

    dbg("registering slot %s", slot->hotplug_slot->name);
    - status = pci_hp_register(slot->hotplug_slot);
    + status = pci_hp_register(slot->hotplug_slot, bus, i);
    if (status) {
    err("pci_hp_register failed with error %d", status);
    goto error_name;
    diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
    index a96b739..67f6a0c 100644
    --- a/drivers/pci/hotplug/cpqphp_core.c
    +++ b/drivers/pci/hotplug/cpqphp_core.c
    @@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
    slot->bus, slot->device,
    slot->number, ctrl->slot_device_offset,
    slot_number);
    - result = pci_hp_register(hotplug_slot);
    + result = pci_hp_register(hotplug_slot,
    + ctrl->pci_dev->subordinate,
    + slot->device);
    if (result) {
    err("pci_hp_register failed with error %d\n", result);
    goto error_name;
    diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
    index 996c942..405c608 100644
    --- a/drivers/pci/hotplug/fakephp.c
    +++ b/drivers/pci/hotplug/fakephp.c
    @@ -120,7 +120,7 @@ static int add_slot(struct pci_dev *dev)
    slot->release = &dummy_release;
    slot->private = dslot;

    - retval = pci_hp_register(slot);
    + retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn));
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_dslot;
    diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
    index 600ed7b..eb7a1c0 100644
    --- a/drivers/pci/hotplug/ibmphp_ebda.c
    +++ b/drivers/pci/hotplug/ibmphp_ebda.c
    @@ -1000,7 +1000,8 @@ static int __init ebda_rsrc_controller (void)
    tmp_slot = list_entry (list, struct slot, ibm_slot_list);

    snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
    - pci_hp_register (tmp_slot->hotplug_slot);
    + pci_hp_register(tmp_slot->hotplug_slot,
    + pci_find_bus(0, tmp_slot->bus), tmp_slot->device);
    }

    print_ebda_hpc ();
    diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
    index 01c351c..1be5b0d 100644
    --- a/drivers/pci/hotplug/pci_hotplug_core.c
    +++ b/drivers/pci/hotplug/pci_hotplug_core.c
    @@ -40,6 +40,7 @@
    #include
    #include
    #include
    +#include "../pci.h"

    #define MY_NAME "pci_hotplug"

    @@ -61,43 +62,6 @@ static int debug;

    static LIST_HEAD(pci_hotplug_slot_list);

    -struct kset pci_hotplug_slots_subsys;
    -
    -static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
    - struct attribute *attr, char *buf)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
    - return attribute->show ? attribute->show(slot, buf) : -EIO;
    -}
    -
    -static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
    - struct attribute *attr, const char *buf, size_t len)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
    - return attribute->store ? attribute->store(slot, buf, len) : -EIO;
    -}
    -
    -static struct sysfs_ops hotplug_slot_sysfs_ops = {
    - .show = hotplug_slot_attr_show,
    - .store = hotplug_slot_attr_store,
    -};
    -
    -static void hotplug_slot_release(struct kobject *kobj)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - if (slot->release)
    - slot->release(slot);
    -}
    -
    -static struct kobj_type hotplug_slot_ktype = {
    - .sysfs_ops = &hotplug_slot_sysfs_ops,
    - .release = &hotplug_slot_release,
    -};
    -
    -decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
    -
    /* these strings match up with the values in pci_bus_speed */
    static char *pci_bus_speed_strings[] = {
    "33 MHz PCI", /* 0x00 */
    @@ -151,16 +115,15 @@ GET_STATUS(power_status, u8)
    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)

    -static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t power_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_power_status (slot, &value);
    + retval = get_power_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -168,9 +131,10 @@ exit:
    return retval;
    }

    -static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    unsigned long lpower;
    u8 power;
    int retval = 0;
    @@ -206,29 +170,30 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_power = {
    +static struct pci_slot_attribute hotplug_slot_attr_power = {
    .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .show = power_read_file,
    .store = power_write_file
    };

    -static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_attention_status (slot, &value);
    + retval = get_attention_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    - retval = sprintf (buf, "%d\n", value);
    + retval = sprintf(buf, "%d\n", value);

    exit:
    return retval;
    }

    -static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot_ops *ops = slot->hotplug->ops;
    unsigned long lattention;
    u8 attention;
    int retval = 0;
    @@ -237,13 +202,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
    attention = (u8)(lattention & 0xff);
    dbg (" - attention = %d\n", attention);

    - if (!try_module_get(slot->ops->owner)) {
    + if (!try_module_get(ops->owner)) {
    retval = -ENODEV;
    goto exit;
    }
    - if (slot->ops->set_attention_status)
    - retval = slot->ops->set_attention_status(slot, attention);
    - module_put(slot->ops->owner);
    + if (ops->set_attention_status)
    + retval = ops->set_attention_status(slot->hotplug, attention);
    + module_put(ops->owner);

    exit:
    if (retval)
    @@ -251,18 +216,18 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
    +static struct pci_slot_attribute hotplug_slot_attr_attention = {
    .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .show = attention_read_file,
    .store = attention_write_file
    };

    -static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_latch_status (slot, &value);
    + retval = get_latch_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -271,17 +236,17 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
    +static struct pci_slot_attribute hotplug_slot_attr_latch = {
    .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
    .show = latch_read_file,
    };

    -static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_adapter_status (slot, &value);
    + retval = get_adapter_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -290,42 +255,20 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
    +static struct pci_slot_attribute hotplug_slot_attr_presence = {
    .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
    .show = presence_read_file,
    };

    -static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
    -{
    - int retval;
    - u32 address;
    -
    - retval = get_address (slot, &address);
    - if (retval)
    - goto exit;
    - retval = sprintf (buf, "%04x:%02x:%02x\n",
    - (address >> 16) & 0xffff,
    - (address >> 8) & 0xff,
    - address & 0xff);
    -
    -exit:
    - return retval;
    -}
    -
    -static struct hotplug_slot_attribute hotplug_slot_attr_address = {
    - .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
    - .show = address_read_file,
    -};
    -
    static char *unknown_speed = "Unknown bus speed";

    -static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
    {
    char *speed_string;
    int retval;
    enum pci_bus_speed value;

    - retval = get_max_bus_speed (slot, &value);
    + retval = get_max_bus_speed(slot->hotplug, &value);
    if (retval)
    goto exit;

    @@ -340,18 +283,18 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
    +static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
    .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
    .show = max_bus_speed_read_file,
    };

    -static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
    {
    char *speed_string;
    int retval;
    enum pci_bus_speed value;

    - retval = get_cur_bus_speed (slot, &value);
    + retval = get_cur_bus_speed(slot->hotplug, &value);
    if (retval)
    goto exit;

    @@ -366,14 +309,15 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
    +static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
    .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
    .show = cur_bus_speed_read_file,
    };

    -static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    unsigned long ltest;
    u32 test;
    int retval = 0;
    @@ -396,13 +340,14 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_test = {
    +static struct pci_slot_attribute hotplug_slot_attr_test = {
    .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .store = test_write_file
    };

    -static int has_power_file (struct hotplug_slot *slot)
    +static int has_power_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if ((slot->ops->enable_slot) ||
    @@ -412,8 +357,9 @@ static int has_power_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_attention_file (struct hotplug_slot *slot)
    +static int has_attention_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if ((slot->ops->set_attention_status) ||
    @@ -422,8 +368,9 @@ static int has_attention_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_latch_file (struct hotplug_slot *slot)
    +static int has_latch_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_latch_status)
    @@ -431,8 +378,9 @@ static int has_latch_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_adapter_file (struct hotplug_slot *slot)
    +static int has_adapter_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_adapter_status)
    @@ -440,17 +388,9 @@ static int has_adapter_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_address_file (struct hotplug_slot *slot)
    -{
    - if ((!slot) || (!slot->ops))
    - return -ENODEV;
    - if (slot->ops->get_address)
    - return 0;
    - return -ENOENT;
    -}
    -
    -static int has_max_bus_speed_file (struct hotplug_slot *slot)
    +static int has_max_bus_speed_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_max_bus_speed)
    @@ -458,8 +398,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_cur_bus_speed_file (struct hotplug_slot *slot)
    +static int has_cur_bus_speed_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_cur_bus_speed)
    @@ -467,8 +408,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_test_file (struct hotplug_slot *slot)
    +static int has_test_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->hardware_test)
    @@ -476,7 +418,7 @@ static int has_test_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int fs_add_slot (struct hotplug_slot *slot)
    +static int fs_add_slot(struct pci_slot *slot)
    {
    int retval = 0;

    @@ -507,13 +449,6 @@ static int fs_add_slot (struct hotplug_slot *slot)
    goto exit_adapter;
    }

    - if (has_address_file(slot) == 0) {
    - retval = sysfs_create_file(&slot->kobj,
    - &hotplug_slot_attr_address.attr);
    - if (retval)
    - goto exit_address;
    - }
    -
    if (has_max_bus_speed_file(slot) == 0) {
    retval = sysfs_create_file(&slot->kobj,
    &hotplug_slot_attr_max_bus_speed.attr);
    @@ -546,10 +481,6 @@ exit_cur_speed:
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);

    exit_max_speed:
    - if (has_address_file(slot) == 0)
    - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
    -
    -exit_address:
    if (has_adapter_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);

    @@ -569,7 +500,7 @@ exit:
    return retval;
    }

    -static void fs_remove_slot (struct hotplug_slot *slot)
    +static void fs_remove_slot(struct pci_slot *slot)
    {
    if (has_power_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
    @@ -583,9 +514,6 @@ static void fs_remove_slot (struct hotplug_slot *slot)
    if (has_adapter_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);

    - if (has_address_file(slot) == 0)
    - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
    -
    if (has_max_bus_speed_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);

    @@ -609,6 +537,12 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
    return NULL;
    }

    +static void hotplug_release(struct pci_slot *slot)
    +{
    + struct hotplug_slot *hotplug = slot->hotplug;
    + hotplug->release(hotplug);
    +}
    +
    /**
    * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
    * @slot: pointer to the &struct hotplug_slot to register
    @@ -618,8 +552,9 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int pci_hp_register (struct hotplug_slot *slot)
    +int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    {
    + struct pci_slot *pci_slot;
    int result;

    if (slot == NULL)
    @@ -632,18 +567,20 @@ int pci_hp_register (struct hotplug_slot *slot)
    return -EINVAL;
    }

    - kobject_set_name(&slot->kobj, "%s", slot->name);
    - kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
    + pci_slot = pci_create_slot(bus, slot_nr, slot->name);
    + if (IS_ERR(pci_slot))
    + return PTR_ERR(pci_slot);

    - /* this can fail if we have already registered a slot with the same name */
    - if (kobject_register(&slot->kobj)) {
    - err("Unable to register kobject");
    - return -EINVAL;
    - }
    -
    - list_add (&slot->slot_list, &pci_hotplug_slot_list);
    + pci_slot = pci_slot_add_hotplug(bus, slot_nr, hotplug_release);
    + if (IS_ERR(pci_slot))
    + return PTR_ERR(pci_slot);
    +
    + slot->pci_slot = pci_slot;
    + pci_slot->hotplug = slot;

    - result = fs_add_slot (slot);
    + list_add(&slot->slot_list, &pci_hotplug_slot_list);
    +
    + result = fs_add_slot(pci_slot);
    dbg ("Added slot %s to the list\n", slot->name);
    return result;
    }
    @@ -657,22 +594,24 @@ int pci_hp_register (struct hotplug_slot *slot)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int pci_hp_deregister (struct hotplug_slot *slot)
    +int pci_hp_deregister(struct hotplug_slot *hotplug)
    {
    struct hotplug_slot *temp;
    + struct pci_slot *slot;

    - if (slot == NULL)
    + if (!hotplug)
    return -ENODEV;

    - temp = get_slot_from_name (slot->name);
    - if (temp != slot) {
    + temp = get_slot_from_name(hotplug->name);
    + if (temp != hotplug)
    return -ENODEV;
    - }
    - list_del (&slot->slot_list);

    - fs_remove_slot (slot);
    - dbg ("Removed slot %s from the list\n", slot->name);
    - kobject_unregister(&slot->kobj);
    + list_del(&hotplug->slot_list);
    +
    + slot = hotplug->pci_slot;
    + fs_remove_slot(slot);
    + pci_destroy_slot(slot);
    + dbg("Removed slot %s from the list\n", hotplug->name);
    return 0;
    }

    @@ -686,13 +625,15 @@ int pci_hp_deregister (struct hotplug_slot *slot)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
    +int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
    struct hotplug_slot_info *info)
    {
    - if ((slot == NULL) || (info == NULL))
    + struct pci_slot *slot;
    + if (!hotplug || !info)
    return -ENODEV;
    + slot = hotplug->pci_slot;

    - memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
    + memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));

    return 0;
    }
    @@ -701,31 +642,21 @@ static int __init pci_hotplug_init (void)
    {
    int result;

    - kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
    - result = subsystem_register(&pci_hotplug_slots_subsys);
    - if (result) {
    - err("Register subsys with error %d\n", result);
    - goto exit;
    - }
    result = cpci_hotplug_init(debug);
    if (result) {
    err ("cpci_hotplug_init with error %d\n", result);
    - goto err_subsys;
    + goto err_cpci;
    }

    info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
    - goto exit;
    -
    -err_subsys:
    - subsystem_unregister(&pci_hotplug_slots_subsys);
    -exit:
    +
    +err_cpci:
    return result;
    }

    static void __exit pci_hotplug_exit (void)
    {
    cpci_hotplug_exit();
    - subsystem_unregister(&pci_hotplug_slots_subsys);
    }

    module_init(pci_hotplug_init);
    @@ -737,7 +668,6 @@ MODULE_LICENSE("GPL");
    module_param(debug, bool, 0644);
    MODULE_PARM_DESC(debug, "Debugging mode enabled or not");

    -EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
    EXPORT_SYMBOL_GPL(pci_hp_register);
    EXPORT_SYMBOL_GPL(pci_hp_deregister);
    EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
    diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
    index 6462ac3..19aa33e 100644
    --- a/drivers/pci/hotplug/pciehp_core.c
    +++ b/drivers/pci/hotplug/pciehp_core.c
    @@ -69,7 +69,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
    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 *slot, enum pci_bus_speed *value);
    static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);

    @@ -82,7 +81,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
    .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,
    };
    @@ -245,14 +243,16 @@ static int init_slots(struct controller *ctrl)
    dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
    "slot_device_offset=%x\n", slot->bus, slot->device,
    slot->hp_slot, slot->number, ctrl->slot_device_offset);
    - retval = pci_hp_register(hotplug_slot);
    + retval = pci_hp_register(hotplug_slot,
    + ctrl->pci_dev->subordinate,
    + slot->device);
    if (retval) {
    err ("pci_hp_register failed with error %d\n", retval);
    goto error_info;
    }
    /* create additional sysfs entries */
    if (EMI(ctrl->ctrlcap)) {
    - retval = sysfs_create_file(&hotplug_slot->kobj,
    + retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
    &hotplug_slot_attr_lock.attr);
    if (retval) {
    pci_hp_deregister(hotplug_slot);
    @@ -285,7 +285,7 @@ static void cleanup_slots(struct controller *ctrl)
    slot = list_entry(tmp, struct slot, slot_list);
    list_del(&slot->slot_list);
    if (EMI(ctrl->ctrlcap))
    - sysfs_remove_file(&slot->hotplug_slot->kobj,
    + sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
    &hotplug_slot_attr_lock.attr);
    cancel_delayed_work(&slot->work);
    flush_scheduled_work();
    @@ -387,18 +387,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = hotplug_slot->private;
    - struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
    -
    - return 0;
    -}
    -
    static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
    {
    struct slot *slot = hotplug_slot->private;
    diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
    index a080fed..3663507 100644
    --- a/drivers/pci/hotplug/rpadlpar_sysfs.c
    +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
    @@ -23,6 +23,8 @@

    #define MAX_DRC_NAME_LEN 64

    +extern struct kset pci_slots_subsys;
    +
    /* Store return code of dlpar operation in attribute struct */
    struct dlpar_io_attr {
    int rc;
    @@ -130,7 +132,7 @@ struct kobj_type ktype_dlpar_io = {

    struct kset dlpar_io_kset = {
    .kobj = {.ktype = &ktype_dlpar_io,
    - .parent = &pci_hotplug_slots_subsys.kobj},
    + .parent = &pci_slots_subsys.kobj},
    .ktype = &ktype_dlpar_io,
    };

    diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
    index d4ee872..3e1f24b 100644
    --- a/drivers/pci/hotplug/rpaphp_slot.c
    +++ b/drivers/pci/hotplug/rpaphp_slot.c
    @@ -160,7 +160,8 @@ int rpaphp_register_slot(struct slot *slot)
    return -EAGAIN;
    }

    - retval = pci_hp_register(php_slot);
    + retval = pci_hp_register(php_slot, slot->bus,
    + PCI_SLOT(PCI_DN(slot->dn->child)->devfn));
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    return retval;
    diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
    index 693519e..cc74602 100644
    --- a/drivers/pci/hotplug/sgi_hotplug.c
    +++ b/drivers/pci/hotplug/sgi_hotplug.c
    @@ -625,7 +625,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
    bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
    bss_hotplug_slot->release = &sn_release_slot;

    - rc = pci_hp_register(bss_hotplug_slot);
    + rc = pci_hp_register(bss_hotplug_slot, pci_bus, device);
    if (rc)
    goto register_err;
    }
    diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
    index 80dec97..22c4d2e 100644
    --- a/drivers/pci/hotplug/shpchp_core.c
    +++ b/drivers/pci/hotplug/shpchp_core.c
    @@ -65,7 +65,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
    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 *slot, enum pci_bus_speed *value);
    static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);

    @@ -78,7 +77,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
    .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,
    };
    @@ -152,7 +150,8 @@ static int init_slots(struct controller *ctrl)
    dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
    "slot_device_offset=%x\n", slot->bus, slot->device,
    slot->hp_slot, slot->number, ctrl->slot_device_offset);
    - retval = pci_hp_register(slot->hotplug_slot);
    + retval = pci_hp_register(slot->hotplug_slot,
    + ctrl->pci_dev->subordinate, slot->device);
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_info;
    @@ -277,18 +276,6 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = get_slot(hotplug_slot);
    - struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
    -
    - return 0;
    -}
    -
    static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
    {
    struct slot *slot = get_slot(hotplug_slot);
    diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
    index fc87e14..4bcfabf 100644
    --- a/drivers/pci/pci.h
    +++ b/drivers/pci/pci.h
    @@ -91,3 +91,16 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
    }

    struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
    +
    +/* PCI slot sysfs helper code */
    +#define to_pci_slot(s) container_of(s, struct pci_slot, kobj)
    +
    +extern struct kset pci_slots_subsys;
    +
    +struct pci_slot_attribute {
    + struct attribute attr;
    + ssize_t (*show)(struct pci_slot *, char *);
    + ssize_t (*store)(struct pci_slot *, const char *, size_t);
    +};
    +#define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
    +
    diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
    new file mode 100644
    index 0000000..f4ca61b
    --- /dev/null
    +++ b/drivers/pci/slot.c
    @@ -0,0 +1,184 @@
    +/*
    + * drivers/pci/slot.c
    + * Copyright (c) 2006 Matthew Wilcox
    + * Copyright (c) 2006 Hewlett-Packard Company
    + */
    +
    +#include
    +#include
    +#include "pci.h"
    +
    +struct kset pci_slots_subsys;
    +EXPORT_SYMBOL_GPL(pci_slots_subsys);
    +
    +static ssize_t pci_slot_attr_show(struct kobject *kobj,
    + struct attribute *attr, char *buf)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
    + return attribute->show ? attribute->show(slot, buf) : -EIO;
    +}
    +
    +static ssize_t pci_slot_attr_store(struct kobject *kobj,
    + struct attribute *attr, const char *buf, size_t len)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
    + return attribute->store ? attribute->store(slot, buf, len) : -EIO;
    +}
    +
    +static struct sysfs_ops pci_slot_sysfs_ops = {
    + .show = pci_slot_attr_show,
    + .store = pci_slot_attr_store,
    +};
    +
    +static void pci_slot_release(struct kobject *kobj)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + slot->release(slot);
    + kfree(slot);
    +}
    +
    +static struct kobj_type pci_slot_ktype = {
    + .sysfs_ops = &pci_slot_sysfs_ops,
    + .release = &pci_slot_release,
    +};
    +
    +decl_subsys_name(pci_slots, slots, &pci_slot_ktype, NULL);
    +
    +static ssize_t address_read_file(struct pci_slot *slot, char *buf)
    +{
    + return sprintf(buf, "%04x:%02x:%02x\n", pci_domain_nr(slot->bus),
    + slot->bus->number, slot->number);
    +}
    +
    +static struct pci_slot_attribute pci_slot_attr_address = {
    + .attr = { .name = "address", .mode = S_IFREG | S_IRUGO },
    + .show = address_read_file,
    +};
    +
    +static void remove_sysfs_files(struct pci_slot *slot)
    +{
    + sysfs_remove_file(&slot->kobj, &pci_slot_attr_address.attr);
    +}
    +
    +static int create_sysfs_files(struct pci_slot *slot)
    +{
    + int result;
    +
    + result = sysfs_create_file(&slot->kobj, &pci_slot_attr_address.attr);
    +
    + return result;
    +}
    +
    +struct pci_slot *pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    + void (*release)(struct pci_slot *))
    +{
    + struct pci_slot *slot;
    + int found = 0;
    +
    + down_write(&pci_bus_sem);
    +
    + /* This slot should have already been created, so look for it. If
    + * we can't find it, return -EEXIST.
    + */
    + for (slot = parent->slot; slot; slot = slot->next)
    + if (slot->number == slot_nr) {
    + found = 1;
    + break;
    + }
    +
    + if (!found) {
    + slot = ERR_PTR(-EEXIST);
    + goto out;
    + }
    +
    + slot->release = release;
    + out:
    + up_write(&pci_bus_sem);
    + return slot;
    +}
    +EXPORT_SYMBOL_GPL(pci_slot_add_hotplug);
    +
    +struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
    + const char *name)
    +{
    + struct pci_slot *slot;
    + int err;
    +
    + down_write(&pci_bus_sem);
    +
    + /* If we've already created this slot, just return. */
    + for (slot = parent->slot; slot; slot = slot->next) {
    + if (slot->number != slot_nr)
    + continue;
    + goto out;
    + }
    +
    + slot = kzalloc(sizeof(*slot), GFP_KERNEL);
    + if (!slot) {
    + slot = ERR_PTR(-ENOMEM);
    + goto out;
    + }
    +
    + slot->bus = parent;
    + slot->number = slot_nr;
    +
    + kobject_set_name(&slot->kobj, "%s", name);
    + kobj_set_kset_s(slot, pci_slots_subsys);
    + if (kobject_register(&slot->kobj)) {
    + printk(KERN_ERR "Unable to register kobject %s", name);
    + err = -EINVAL;
    + goto err;
    + }
    +
    + err = create_sysfs_files(slot);
    + if (err)
    + goto unregister;
    +
    + slot->next = parent->slot;
    + parent->slot = slot;
    +
    + out:
    + up_write(&pci_bus_sem);
    + return slot;
    +
    + unregister:
    + kobject_unregister(&slot->kobj);
    + err:
    + kfree(slot);
    + slot = ERR_PTR(err);
    + goto out;
    +}
    +EXPORT_SYMBOL_GPL(pci_create_slot);
    +
    +int pci_destroy_slot(struct pci_slot *slot)
    +{
    + struct pci_slot **pprev;
    +
    + for (pprev = &slot->bus->slot; *pprev; pprev = &(*pprev)->next) {
    + if (*pprev == slot) {
    + *pprev = slot->next;
    + break;
    + }
    + }
    +
    + remove_sysfs_files(slot);
    + kobject_unregister(&slot->kobj);
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(pci_destroy_slot);
    +
    +static int pci_slot_init(void)
    +{
    + int result;
    +
    + kobj_set_kset_s(&pci_slots_subsys, pci_bus_type.subsys);
    + result = subsystem_register(&pci_slots_subsys);
    + if (result)
    + printk(KERN_ERR "PCI: Slot initialisation failure (%d)",
    + result);
    + return result;
    +}
    +
    +subsys_initcall(pci_slot_init);
    diff --git a/include/linux/pci.h b/include/linux/pci.h
    index 0dd93bb..ae2245f 100644
    --- a/include/linux/pci.h
    +++ b/include/linux/pci.h
    @@ -129,6 +129,16 @@ struct pci_cap_saved_state {
    u32 data[0];
    };

    +/* pci_slot represents a physical slot */
    +struct pci_slot {
    + struct pci_bus *bus; /* The bus this slot is on */
    + struct pci_slot *next; /* Next slot on this bus */
    + struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */
    + unsigned char number; /* PCI_SLOT(pci_dev->devfn) */
    + struct kobject kobj;
    + void (*release)(struct pci_slot *);
    +};
    +
    /*
    * The pci_dev structure is used to describe PCI devices.
    */
    @@ -140,6 +150,7 @@ struct pci_dev {

    void *sysdata; /* hook for sys-specific extension */
    struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
    + struct pci_slot *slot; /* Physical slot this device is in */

    unsigned int devfn; /* encoded device & function index */
    unsigned short vendor;
    @@ -261,6 +272,7 @@ struct pci_bus {
    struct list_head children; /* list of child buses */
    struct list_head devices; /* list of devices on this bus */
    struct pci_dev *self; /* bridge device as seen by parent */
    + struct pci_slot *slot; /* First physical slot on this bus */
    struct resource *resource[PCI_BUS_NUM_RESOURCES];
    /* address space routed to this bus */

    @@ -470,6 +482,11 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s
    }
    struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
    struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
    +struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
    + const char *name);
    +struct pci_slot *pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    + void (*release)(struct pci_slot *));
    +int pci_destroy_slot(struct pci_slot *slot);
    int pci_scan_slot(struct pci_bus *bus, int devfn);
    struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
    void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
    diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
    index ab4cb6e..bb36c59 100644
    --- a/include/linux/pci_hotplug.h
    +++ b/include/linux/pci_hotplug.h
    @@ -95,9 +95,6 @@ struct hotplug_slot_attribute {
    * @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.
    @@ -120,7 +117,6 @@ struct hotplug_slot_ops {
    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);
    };
    @@ -140,7 +136,6 @@ struct hotplug_slot_info {
    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;
    };
    @@ -166,15 +161,14 @@ struct hotplug_slot {

    /* Variables below this are for use only by the hotplug pci core. */
    struct list_head slot_list;
    - struct kobject kobj;
    + struct pci_slot *pci_slot;
    };
    #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)

    -extern int pci_hp_register (struct hotplug_slot *slot);
    -extern int pci_hp_deregister (struct hotplug_slot *slot);
    +extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr);
    +extern int pci_hp_deregister(struct hotplug_slot *slot);
    extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
    struct hotplug_slot_info *info);
    -extern struct kset pci_hotplug_slots_subsys;

    /* PCI Setting Record (Type 0) */
    struct hpp_type0 {
    --
    1.5.3.1.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  9. Re: [PATCH 0/4, v3] Physical PCI slot objects

    Hi Kristin,

    * Kristen Carlson Accardi :
    > Alex Chiang wrote:
    >
    > > I have done quite a bit more testing, and verified that this
    > > series plays nicely with acpiphp during all stages of the
    > > series. Notably, you can modprobe/rmmod acpiphp repeatedly
    > > no matter where you are in the series, and no matter whether
    > > you have CONFIG_ACPI_PCI_SLOT turned on. The correct entries
    > > in /sys/bus/pci/slots/ will appear and disappear, and we
    > > correctly register/deregister ACPI slots with the pci_hp
    > > core.

    >
    > How does this patch play with non-acpi based hotplug such as
    > the pciehp driver or the shpchp driver for example?


    Thanks for asking these questions -- I fixed some bugs in patches
    3/4 and 4/4 that should lead to a much better experience.

    First, it turns out I did not modify the pciehp driver correctly
    when using the new pci_hp_register interface. I fixed this bug,
    and noticed a problem in the rpaphp driver (which I fixed as
    well). I visually inspected the shpchp driver, and it *seems* to
    be correct, so no change there. I will send these fixes as Patch
    3/4, v4.

    Second, I resolved the issue of what happens when two different
    hp drivers try to claim the same PCI slot. Basically, whoever
    registered the slot first wins, and second place gets a -EBUSY
    return value. I *think* that is the correct behavior, as Willy
    informs me that having two drivers try to claim the same slot is
    badness. These fixes will be sent as Patch 4/4, v4.

    I tested by modprobe/rmmod both acpiphp and pciehp multiple
    times, and in differing orders. I also tested both
    CONFIG_ACPI_PCI_SLOT turned on and off. In all cases, at least
    what I intended to happen did happen.

    Now whether my intentions were correct or misguided might be a
    different story... I'm wondering most about the -EBUSY thing,
    but I don't see a better option.

    Patches 1/4 and 2/4 had no changes so I will not resend them.

    Thanks.

    /ac

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  10. Re: [PATCH 4/4, v4] ACPI, PCI: ACPI PCI slot detection driver

    On Mon, 19 Nov 2007 15:04:18 -0700
    Alex Chiang wrote:

    > Documentation/accounting/getdelays.c | 43 +-
    > Documentation/feature-removal-schedule.txt | 9 -
    > Documentation/hwmon/sysfs-interface | 31 +
    > Documentation/markers.txt | 6 +-
    >


    Clearly something went horrifically wrong here....
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  11. Re: [PATCH 0/4, v3] Physical PCI slot objects

    On Sat, Nov 17, 2007 at 11:29:54AM -0700, Alex Chiang wrote:
    > Hi all,
    >
    > This is v3 of the pci_slot patch series.
    >
    > The major change is making the ACPI-PCI slot driver a Kconfig
    > option, as per the recommendations of others (Gary, Kenji-san).


    Alex, What I was trying to suggest is a boot-time kernel option,
    not a kernel configuration option. The basic idea is to give
    the user (with a single binary kernel) the ability to include
    your ACPI-PCI slot driver feature changes only when they are
    really needed. In addition to reducing the number of
    system/PCI hotplug driver combinations where your changes
    would need to be validated, I believe would also help
    alleviate other worries (e.g. Andi Kleen's memory consumption
    concern). I believe this goal could also be achieved with the
    kernel config option by making the pci_slot module runtime
    loadable with the PCI hotplug drivers only visiting your new
    code when the pci_slot driver is loaded, although I think this
    would be more difficult to implement.

    Also, I notice that even with your current CONFIG_ACPI_PCI_SLOT
    implementation your numerous PCI hotplug driver changes (except
    for only two places in pci_hotplug_core.c where there is
    `#ifndef CONFIG_ACPI_PCI_SLOT` and `#ifdef CONFIG_ACPI_PCI_SLOT`)
    are _always_ exposed. So, even with CONFIG_ACPI_PCI_SLOT disabled
    there is IMO a need for testing of the affected PCI hotplug drivers
    on more than a small number of isolated systems.

    The good news is that I was able to test your v3 changes
    (w/2.6.24-rc3 source) on our x3850 today with 'acpiphp'
    and, except for the above mentioned inability to run-time
    include/exclude them, they seemed to work fine. The previous
    boot-time ACPI error messages are gone and I was able to
    successfully hot-remove and hot-add both PCI-X and PCIe
    adapters.

    Thanks,
    Gary

    --
    Gary Hade
    System x Enablement
    IBM Linux Technology Center
    503-578-4503 IBM T/L: 775-4503
    garyhade@us.ibm.com
    http://www.ibm.com/linux/ltc


    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  12. Re: [PATCH 0/4, v3] Physical PCI slot objects

    Gary Hade ????????:
    > On Sat, Nov 17, 2007 at 11:29:54AM -0700, Alex Chiang wrote:
    >> Hi all,
    >>
    >> This is v3 of the pci_slot patch series.
    >>
    >> The major change is making the ACPI-PCI slot driver a Kconfig
    >> option, as per the recommendations of others (Gary, Kenji-san).

    >
    > Alex, What I was trying to suggest is a boot-time kernel option,
    > not a kernel configuration option. The basic idea is to give
    > the user (with a single binary kernel) the ability to include
    > your ACPI-PCI slot driver feature changes only when they are
    > really needed. In addition to reducing the number of
    > system/PCI hotplug driver combinations where your changes
    > would need to be validated, I believe would also help
    > alleviate other worries (e.g. Andi Kleen's memory consumption
    > concern). I believe this goal could also be achieved with the
    > kernel config option by making the pci_slot module runtime
    > loadable with the PCI hotplug drivers only visiting your new
    > code when the pci_slot driver is loaded, although I think this
    > would be more difficult to implement.
    >


    I agree to Gary very much.

    Thanks,
    Kenji Kaneshige



    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  13. Re: [PATCH 0/4, v3] Physical PCI slot objects

    On Mon, Nov 19, 2007 at 03:32:25PM -0800, Gary Hade wrote:

    > Alex, What I was trying to suggest is a boot-time kernel option,
    > not a kernel configuration option. The basic idea is to give
    > the user (with a single binary kernel) the ability to include
    > your ACPI-PCI slot driver feature changes only when they are
    > really needed. In addition to reducing the number of
    > system/PCI hotplug driver combinations where your changes
    > would need to be validated, I believe would also help
    > alleviate other worries (e.g. Andi Kleen's memory consumption
    > concern). I believe this goal could also be achieved with the
    > kernel config option by making the pci_slot module runtime
    > loadable with the PCI hotplug drivers only visiting your new
    > code when the pci_slot driver is loaded, although I think this
    > would be more difficult to implement.


    If we're compiling something into the kernel, the default behaviour
    should be for the functionality to be turned on unless the user
    overrides it.

    --
    Matthew Garrett | mjg59@srcf.ucam.org
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  14. Re: [PATCH 4/4, v4] ACPI, PCI: ACPI PCI slot detection driver

    * Kristen Carlson Accardi :
    > On Mon, 19 Nov 2007 15:04:18 -0700
    > Alex Chiang wrote:
    >
    > > Documentation/accounting/getdelays.c | 43 +-
    > > Documentation/feature-removal-schedule.txt | 9 -
    > > Documentation/hwmon/sysfs-interface | 31 +
    > > Documentation/markers.txt | 6 +-
    > >

    >
    > Clearly something went horrifically wrong here....


    Ugh, seems that stacked git got very confused when I did a
    git-fetch && git-rebase origin. Also, guess it figures that I
    shouldn't try and send a patch as I'm running out the door. :-/
    Sorry about that.

    Here is the correct version of Patch 4/4, v4. Note the small
    changes in acpiphp and pciehp to disregard -EBUSY as an error
    condition when returned from pci_hp_register. If you try and load
    both drivers, whoever is in 2nd place will let you know that
    another driver has already claimed the slot.

    I didn't have the courage to go through and modify all the other
    pcihp drivers, so if you have a system with both acpiphp and
    shpcphp/cpciphp/etc., the dmesg output may be a little noisy (but
    the behavior should be correct).

    I'll have to digest Gary's recommendation for a boot-time kernel
    option tomorrow.

    Thanks.

    From: 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.

    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
    ---
    drivers/acpi/Kconfig | 9 ++
    drivers/acpi/Makefile | 1 +
    drivers/acpi/pci_slot.c | 203 ++++++++++++++++++++++++++++++++
    drivers/pci/hotplug/acpiphp_core.c | 2 +
    drivers/pci/hotplug/acpiphp_glue.c | 7 +-
    drivers/pci/hotplug/pci_hotplug_core.c | 22 +++-
    drivers/pci/hotplug/pciehp_core.c | 11 ++-
    drivers/pci/slot.c | 5 +
    9 files changed, 256 insertions(+), 6 deletions(-)
    create mode 100644 drivers/acpi/pci_slot.c

    diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
    index ce9dead..c6da1e0 100644
    --- a/drivers/acpi/Kconfig
    +++ b/drivers/acpi/Kconfig
    @@ -292,6 +292,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 0000000..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 for much guidance.
    + *
    + * Copyright (C) 2007 Alex Chiang
    + * 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, &adr);
    + if (ACPI_FAILURE(status))
    + return AE_OK;
    + device = (adr >> 16) & 0xffff;
    +
    + /* No _SUN == not a slot == bail */
    + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
    + if (ACPI_FAILURE(status))
    + 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));
    + return AE_OK;
    + }
    +
    + return AE_OK;
    +}
    +
    +/*
    + * find_p2p_bridge - callback function to discover p2p bridges
    + */
    +static acpi_status
    +find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
    +{
    + int device, function;
    + unsigned long adr;
    + acpi_status status;
    + acpi_handle dummy_handle;
    +
    + struct pci_dev *dev;
    + struct pci_bus *pci_bus = context;
    +
    + 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;
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + register_slot, dev->subordinate, NULL);
    + if (ACPI_FAILURE(status))
    + goto out;
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + find_p2p_bridge, dev->subordinate, NULL);
    +out:
    + pci_dev_put(dev);
    + return AE_OK;
    +}
    +
    +#define ACPI_STA_FUNCTIONING (0x00000008)
    +
    +/*
    + * acpi_pci_slot_add - walk namespace under a PCI root bridge
    + * @handle: points to an acpi_pci_root
    + */
    +static int
    +acpi_pci_slot_add(acpi_handle handle)
    +{
    + int seg, bus;
    + unsigned long tmp;
    + acpi_status status;
    + acpi_handle dummy_handle;
    + struct pci_bus *pci_bus;
    +
    + /* 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;
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + register_slot, pci_bus, NULL);
    + if (ACPI_FAILURE(status)) {
    + err("%s: register_slot failure - %d\n", __FUNCTION__, status);
    + return status;
    + }
    +
    + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
    + find_p2p_bridge, pci_bus, NULL);
    + if (ACPI_FAILURE(status))
    + err("%s: find_p2p_bridge failure - %d\n", __FUNCTION__, status);
    +
    + return status;
    +}
    +
    +static int __init
    +acpi_pci_slot_init(void)
    +{
    + acpi_pci_register_driver(&acpi_pci_slot_driver);
    + return 0;
    +}
    +
    +/*
    + * acpi_pci_slot_remove and acpi_pci_slot_exit are empty for now, since
    + * /sys/bus/pci/slots/ entries shouldn't ever really go away.
    + */
    +static void
    +acpi_pci_slot_remove(acpi_handle handle)
    +{
    +}
    +
    +static void __exit
    +acpi_pci_slot_exit(void)
    +{
    +}
    +
    +module_init(acpi_pci_slot_init);
    +module_exit(acpi_pci_slot_exit);
    diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
    index 34b8d0b..518dcd6 100644
    --- a/drivers/pci/hotplug/acpiphp_core.c
    +++ b/drivers/pci/hotplug/acpiphp_core.c
    @@ -346,6 +346,8 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
    retval = pci_hp_register(slot->hotplug_slot,
    acpiphp_slot->bridge->pci_bus,
    acpiphp_slot->device);
    + if (retval == -EBUSY)
    + goto error_hpslot;
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_hpslot;
    diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
    index 02a2fd7..bb0eada 100644
    --- a/drivers/pci/hotplug/acpiphp_glue.c
    +++ b/drivers/pci/hotplug/acpiphp_glue.c
    @@ -259,7 +259,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
    bridge->pci_bus->number, slot->device);
    retval = acpiphp_register_hotplug_slot(slot);
    if (retval) {
    - warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval);
    + if (retval == -EBUSY)
    + warn("Slot %d already registered by another "
    + "hotplug driver\n", slot->sun);
    + else
    + warn("acpiphp_register_hotplug_slot failed "
    + "(err code = 0x%x)\n", retval);
    goto err_exit;
    }
    }
    diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
    index 1be5b0d..61ade06 100644
    --- a/drivers/pci/hotplug/pci_hotplug_core.c
    +++ b/drivers/pci/hotplug/pci_hotplug_core.c
    @@ -567,6 +567,14 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    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 just return without error.
    + *
    + * We need this second call if we haven't already created the
    + * pci_slot (in the case of native PCIe hp slot).
    + */
    pci_slot = pci_create_slot(bus, slot_nr, slot->name);
    if (IS_ERR(pci_slot))
    return PTR_ERR(pci_slot);
    @@ -581,7 +589,7 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    list_add(&slot->slot_list, &pci_hotplug_slot_list);

    result = fs_add_slot(pci_slot);
    - dbg ("Added slot %s to the list\n", slot->name);
    + dbg("Added slot %s to the list\n", slot->name);
    return result;
    }

    @@ -610,8 +618,18 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)

    slot = hotplug->pci_slot;
    fs_remove_slot(slot);
    - pci_destroy_slot(slot);
    dbg("Removed slot %s from the list\n", hotplug->name);
    +#ifdef CONFIG_ACPI_PCI_SLOT
    + /*
    + * If we are using the ACPI-PCI slot driver, we don't want to
    + * destroy the pci_slot object. Rather, just release the
    + * hotplug_slot associated with it.
    + */
    + hotplug_release(slot);
    + slot->release = NULL;
    +#else
    + pci_destroy_slot(slot);
    +#endif
    return 0;
    }

    diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
    index 19aa33e..299f6fa 100644
    --- a/drivers/pci/hotplug/pciehp_core.c
    +++ b/drivers/pci/hotplug/pciehp_core.c
    @@ -246,8 +246,10 @@ static int init_slots(struct controller *ctrl)
    retval = pci_hp_register(hotplug_slot,
    ctrl->pci_dev->subordinate,
    slot->device);
    + 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 */
    @@ -452,7 +454,12 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
    /* Setup the slot information structures */
    rc = init_slots(ctrl);
    if (rc) {
    - err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
    + if (rc == -EBUSY)
    + warn("%s: slot already registered by another "
    + "hotplug driver\n", PCIE_MODULE_NAME);
    + else
    + err("%s: slot initialization failed\n",
    + PCIE_MODULE_NAME);
    goto err_out_release_ctlr;
    }

    diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
    index f4ca61b..d2dc5dd 100644
    --- a/drivers/pci/slot.c
    +++ b/drivers/pci/slot.c
    @@ -93,6 +93,11 @@ struct pci_slot *pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    goto out;
    }

    + if (slot->release) {
    + slot = ERR_PTR(-EBUSY);
    + goto out;
    + }
    +
    slot->release = release;
    out:
    up_write(&pci_bus_sem);
    --
    1.5.3.1.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  15. stgit (was Re: [PATCH 4/4, v4] ACPI, PCI: ACPI PCI slot detection driver)

    On Mon, 19 Nov 2007, Alex Chiang wrote:
    > Ugh, seems that stacked git got very confused when I did a
    > git-fetch && git-rebase origin. Also, guess it figures that I


    Being a very heavy stgit user myself, I have to say you must give up git
    rebase on any stgit branch, and use stg rebase instead... otherwise, bad
    things can, and do happen.

    Also, don't trust the stgit release schedule, it is "release eventually" and
    not something more sensible, like "release often". Instead, track the stgit
    git tree.

    I wish git learned to do the basic stgit's business by itself

    --
    "One disk to rule them all, One disk to find them. One disk to bring
    them all and in the darkness grind them. In the Land of Redmond
    where the shadows lie." -- The Silicon Valley Tarot
    Henrique Holschuh
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  16. Re: [PATCH 0/4, v3] Physical PCI slot objects

    On Tue, Nov 20, 2007 at 02:04:02AM +0000, Matthew Garrett wrote:
    > On Mon, Nov 19, 2007 at 03:32:25PM -0800, Gary Hade wrote:
    >
    > > Alex, What I was trying to suggest is a boot-time kernel option,
    > > not a kernel configuration option. The basic idea is to give
    > > the user (with a single binary kernel) the ability to include
    > > your ACPI-PCI slot driver feature changes only when they are
    > > really needed. In addition to reducing the number of
    > > system/PCI hotplug driver combinations where your changes
    > > would need to be validated, I believe would also help
    > > alleviate other worries (e.g. Andi Kleen's memory consumption
    > > concern). I believe this goal could also be achieved with the
    > > kernel config option by making the pci_slot module runtime
    > > loadable with the PCI hotplug drivers only visiting your new
    > > code when the pci_slot driver is loaded, although I think this
    > > would be more difficult to implement.

    >
    > If we're compiling something into the kernel, the default behaviour
    > should be for the functionality to be turned on unless the user
    > overrides it.


    It seems like others could have a problem with this but as
    long as there is a way to exclude the functionality in the
    event of problems without a kernel rebuild, "on" by default
    would work for me.

    Thanks,
    Gary

    --
    Gary Hade
    System x Enablement
    IBM Linux Technology Center
    503-578-4503 IBM T/L: 775-4503
    garyhade@us.ibm.com
    http://www.ibm.com/linux/ltc

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  17. [PATCH 4/4, v5] 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.

    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
    ---
    drivers/acpi/Kconfig | 9 +
    drivers/acpi/Makefile | 1 +
    drivers/acpi/pci_slot.c | 294 ++++++++++++++++++++++++++++++++
    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, 316 insertions(+), 3 deletions(-)
    create mode 100644 drivers/acpi/pci_slot.c

    diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
    index ce9dead..f1eae4f 100644
    --- a/drivers/acpi/Kconfig
    +++ b/drivers/acpi/Kconfig
    @@ -292,6 +292,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
    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 0000000..724f4f0
    --- /dev/null
    +++ b/drivers/acpi/pci_slot.c
    @@ -0,0 +1,294 @@
    +/*
    + * pci_slot.c - ACPI PCI Slot Driver
    + *
    + * The code here is heavily leveraged from the acpiphp module.
    + * Thanks to Matthew Wilcox for much guidance.
    + *
    + * Copyright (C) 2007 Alex Chiang
    + * 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 DRIVER_VERSION "0.1"
    +#define DRIVER_AUTHOR "Alex Chiang "
    +#define DRIVER_DESC "ACPI PCI Slot Detection Driver"
    +MODULE_AUTHOR(DRIVER_AUTHOR);
    +MODULE_DESCRIPTION(DRIVER_DESC);
    +MODULE_LICENSE("GPL");
    +
    +#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,
    +};
    +
    +static int
    +check_slot(acpi_handle handle, int *device, unsigned long *sun)
    +{
    + unsigned long adr;
    + acpi_status status;
    +
    + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr);
    + if (ACPI_FAILURE(status))
    + return -1;
    + *device = (adr >> 16) & 0xffff;
    +
    + /* No _SUN == not a slot == bail */
    + status = acpi_evaluate_integer(handle, "_SUN", NULL, sun);
    + if (ACPI_FAILURE(status))
    + return -1;
    +
    + return 0;
    +}
    +
    +/*
    + * 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));
    +
    + 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;
    +
    + 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;
    +
    + 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);
    diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
    index 9a259eb..5dd8e12 100644
    --- a/drivers/pci/hotplug/pci_hotplug_core.c
    +++ b/drivers/pci/hotplug/pci_hotplug_core.c
    @@ -567,6 +567,11 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    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);
    @@ -612,8 +617,12 @@ int pci_hp_deregister(struct hotplug_slot *hotplug)

    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;
    }

    diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
    index 0e9eaf6..299f6fa 100644
    --- a/drivers/pci/hotplug/pciehp_core.c
    +++ b/drivers/pci/hotplug/pciehp_core.c
    @@ -249,7 +249,7 @@ static int init_slots(struct controller *ctrl)
    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 */
    --
    1.5.3.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  18. Re: [PATCH 0/4, v3] Physical PCI slot objects

    Hi Gary, Kenji-san, et. al,

    * Gary Hade :
    >
    > Alex, What I was trying to suggest is a boot-time kernel
    > option, not a kernel configuration option. The basic idea is
    > to give the user (with a single binary kernel) the ability to
    > include your ACPI-PCI slot driver feature changes only when
    > they are really needed. In addition to reducing the number of
    > system/PCI hotplug driver combinations where your changes would
    > need to be validated, I believe would also help alleviate other
    > worries (e.g. Andi Kleen's memory consumption concern). I
    > believe this goal could also be achieved with the kernel config
    > option by making the pci_slot module runtime loadable with the
    > PCI hotplug drivers only visiting your new code when the
    > pci_slot driver is loaded, although I think this would be more
    > difficult to implement.


    I have modified my patch series so that the final patch that
    introduces my ACPI-PCI slot driver is a full-fledged module, that
    has a tristate Kconfig option.

    It can be modprobe'd/rmmod'ed in any combination, and in any
    order with other PCI hotplug modules. There is no ordering
    dependency, even at module unload time, so you can safely rmmod
    pci_slot, and safely continue using features provided by the PCI
    hotplug drivers (acpiphp, pciehp, etc.). The opposite works too.

    The one limitation is that two separate hotplug drivers cannot
    both claim the same device (2nd module loaded will get -EBUSY
    errors), but I do not believe that is a regression from current
    behavior.

    I have only tested with acpiphp and pciehp, as that's the only
    hardware I have, but I believe my code will play nicely with the
    other PCI hp drivers as well.

    The patch series is fully bisectable, and the correct behavior
    occurs no matter which patch you happen to have applied.

    I'll be sending v5 of patches 3 and 4 shortly (patches 1 and 2
    did not change). It is still based on 2.6.24-rc2, because I was
    too scared to do another git rebase while using stgit. :-/

    > Also, I notice that even with your current CONFIG_ACPI_PCI_SLOT
    > implementation your numerous PCI hotplug driver changes (except
    > for only two places in pci_hotplug_core.c where there is
    > `#ifndef CONFIG_ACPI_PCI_SLOT` and `#ifdef CONFIG_ACPI_PCI_SLOT`)
    > are _always_ exposed. So, even with CONFIG_ACPI_PCI_SLOT disabled
    > there is IMO a need for testing of the affected PCI hotplug drivers
    > on more than a small number of isolated systems.


    You are, of course, correct.

    In my opinion, though, I would say most of the changes to the PCI
    hotplug drivers themselves are pretty straightforward, as in
    removing the different ways of getting the PCI address.

    The scary part of the changes (aside from the ACPI-PCI slot
    driver) revolve around the new struct pci_slot, which is
    relatively self-contained, and only expose themselves via the
    pci_create_slot/pci_destroy_slot interfaces which only the PCI
    hotplug corecares about.

    Regardless, your point stands. How do you suggest I get more
    testing time? Is this patchset appropriate for the -mm tree yet?
    Or do you think it still needs more work?

    > The good news is that I was able to test your v3 changes
    > (w/2.6.24-rc3 source) on our x3850 today with 'acpiphp' and,
    > except for the above mentioned inability to run-time
    > include/exclude them, they seemed to work fine. The previous
    > boot-time ACPI error messages are gone and I was able to
    > successfully hot-remove and hot-add both PCI-X and PCIe
    > adapters.


    Thanks for testing. Please let me know how v5 works for you too.

    chers,

    /ac

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  19. [PATCH 3/4, v5] PCI, PCI Hotplug: Introduce pci_slot

    - Make pci_slot the primary sysfs entity. hotplug_slot becomes a
    subsidiary structure.
    o pci_create_slot() creates and registers a slot with the PCI core
    o pci_slot_add_hotplug() gives it hotplug capability

    - Change the prototype of pci_hp_register() to take the bus and
    slot number (on parent bus) as parameters.

    - Remove all the ->get_address methods since this functionality is
    now handled by pci_slot directly.

    v4 -> v5:
    Add refcounting for pci_slot objects.

    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.

    v3 -> v4:
    Fixed bug with pciehp and rpaphp registering slots

    v2 -> v3:
    Separated slot creation and slot hotplug ability into two
    interfaces. Fixed bugs in pci_destroy_slot(), and now
    properly calling from pci_hp_deregister.

    v1 -> v2:
    No change

    Signed-off-by: Alex Chiang
    Signed-off-by: Matthew Wilcox
    ---
    drivers/pci/Makefile | 2 +-
    drivers/pci/hotplug/acpiphp.h | 1 -
    drivers/pci/hotplug/acpiphp_core.c | 25 +---
    drivers/pci/hotplug/acpiphp_glue.c | 23 +--
    drivers/pci/hotplug/acpiphp_ibm.c | 5 +-
    drivers/pci/hotplug/cpci_hotplug_core.c | 2 +-
    drivers/pci/hotplug/cpqphp_core.c | 4 +-
    drivers/pci/hotplug/fakephp.c | 2 +-
    drivers/pci/hotplug/ibmphp_ebda.c | 3 +-
    drivers/pci/hotplug/pci_hotplug_core.c | 244 +++++++++++--------------------
    drivers/pci/hotplug/pciehp_core.c | 31 ++---
    drivers/pci/hotplug/rpadlpar_sysfs.c | 4 +-
    drivers/pci/hotplug/rpaphp_slot.c | 3 +-
    drivers/pci/hotplug/sgi_hotplug.c | 2 +-
    drivers/pci/hotplug/shpchp_core.c | 17 +--
    drivers/pci/pci.h | 13 ++
    drivers/pci/slot.c | 197 +++++++++++++++++++++++++
    include/linux/pci.h | 17 ++
    include/linux/pci_hotplug.h | 12 +-
    19 files changed, 361 insertions(+), 246 deletions(-)
    create mode 100644 drivers/pci/slot.c

    diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
    index 5550556..12f0b2d 100644
    --- a/drivers/pci/Makefile
    +++ b/drivers/pci/Makefile
    @@ -2,7 +2,7 @@
    # Makefile for the PCI bus specific drivers.
    #

    -obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \
    +obj-y += access.o bus.o probe.o remove.o pci.o quirks.o slot.o \
    pci-driver.o search.o pci-sysfs.o rom.o setup-res.o
    obj-$(CONFIG_PROC_FS) += proc.o

    diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
    index f6cc0c5..ab46189 100644
    --- a/drivers/pci/hotplug/acpiphp.h
    +++ b/drivers/pci/hotplug/acpiphp.h
    @@ -216,7 +216,6 @@ extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
    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);

    /* variables */
    extern int acpiphp_debug;
    diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
    index a0ca63a..518dcd6 100644
    --- a/drivers/pci/hotplug/acpiphp_core.c
    +++ b/drivers/pci/hotplug/acpiphp_core.c
    @@ -70,7 +70,6 @@ static int disable_slot (struct hotplug_slot *slot);
    static int set_attention_status (struct hotplug_slot *slot, u8 value);
    static int get_power_status (struct hotplug_slot *slot, u8 *value);
    static int get_attention_status (struct hotplug_slot *slot, u8 *value);
    -static int get_address (struct hotplug_slot *slot, u32 *value);
    static int get_latch_status (struct hotplug_slot *slot, u8 *value);
    static int get_adapter_status (struct hotplug_slot *slot, u8 *value);

    @@ -83,7 +82,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
    .get_attention_status = get_attention_status,
    .get_latch_status = get_latch_status,
    .get_adapter_status = get_adapter_status,
    - .get_address = get_address,
    };


    @@ -279,23 +277,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -
    -/**
    - * get_address - get pci address of a slot
    - * @hotplug_slot: slot to get status
    - * @value: pointer to struct pci_busdev (seg, bus, dev)
    - */
    -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = hotplug_slot->private;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = acpiphp_get_address(slot->acpi_slot);
    -
    - return 0;
    -}
    -
    static int __init init_acpi(void)
    {
    int retval;
    @@ -362,7 +343,11 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
    acpiphp_slot->slot = slot;
    snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun);

    - retval = pci_hp_register(slot->hotplug_slot);
    + retval = pci_hp_register(slot->hotplug_slot,
    + acpiphp_slot->bridge->pci_bus,
    + acpiphp_slot->device);
    + if (retval == -EBUSY)
    + goto error_hpslot;
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_hpslot;
    diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
    index 1e125b5..bb0eada 100644
    --- a/drivers/pci/hotplug/acpiphp_glue.c
    +++ b/drivers/pci/hotplug/acpiphp_glue.c
    @@ -259,7 +259,12 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
    bridge->pci_bus->number, slot->device);
    retval = acpiphp_register_hotplug_slot(slot);
    if (retval) {
    - warn("acpiphp_register_hotplug_slot failed(err code = 0x%x)\n", retval);
    + if (retval == -EBUSY)
    + warn("Slot %d already registered by another "
    + "hotplug driver\n", slot->sun);
    + else
    + warn("acpiphp_register_hotplug_slot failed "
    + "(err code = 0x%x)\n", retval);
    goto err_exit;
    }
    }
    @@ -1874,19 +1879,3 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)

    return (sta == 0) ? 0 : 1;
    }
    -
    -
    -/*
    - * pci address (seg/bus/dev)
    - */
    -u32 acpiphp_get_address(struct acpiphp_slot *slot)
    -{
    - u32 address;
    - struct pci_bus *pci_bus = slot->bridge->pci_bus;
    -
    - address = (pci_domain_nr(pci_bus) << 16) |
    - (pci_bus->number << 8) |
    - slot->device;
    -
    - return address;
    -}
    diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
    index 56829f8..927b1fb 100644
    --- a/drivers/pci/hotplug/acpiphp_ibm.c
    +++ b/drivers/pci/hotplug/acpiphp_ibm.c
    @@ -35,6 +35,7 @@
    #include

    #include "acpiphp.h"
    +extern struct kset pci_slots_subsys;

    #define DRIVER_VERSION "1.0.1"
    #define DRIVER_AUTHOR "Irene Zubarev , Vernon Mauery "
    @@ -428,7 +429,7 @@ static int __init ibm_acpiphp_init(void)
    int retval = 0;
    acpi_status status;
    struct acpi_device *device;
    - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
    + struct kobject *sysdir = &pci_slots_subsys.kobj;

    dbg("%s\n", __FUNCTION__);

    @@ -475,7 +476,7 @@ init_return:
    static void __exit ibm_acpiphp_exit(void)
    {
    acpi_status status;
    - struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
    + struct kobject *sysdir = &pci_slots_subsys.kobj;

    dbg("%s\n", __FUNCTION__);

    diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
    index ed4d44e..aa47b80 100644
    --- a/drivers/pci/hotplug/cpci_hotplug_core.c
    +++ b/drivers/pci/hotplug/cpci_hotplug_core.c
    @@ -285,7 +285,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
    info->attention_status = cpci_get_attention_status(slot);

    dbg("registering slot %s", slot->hotplug_slot->name);
    - status = pci_hp_register(slot->hotplug_slot);
    + status = pci_hp_register(slot->hotplug_slot, bus, i);
    if (status) {
    err("pci_hp_register failed with error %d", status);
    goto error_name;
    diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
    index a96b739..67f6a0c 100644
    --- a/drivers/pci/hotplug/cpqphp_core.c
    +++ b/drivers/pci/hotplug/cpqphp_core.c
    @@ -434,7 +434,9 @@ static int ctrl_slot_setup(struct controller *ctrl,
    slot->bus, slot->device,
    slot->number, ctrl->slot_device_offset,
    slot_number);
    - result = pci_hp_register(hotplug_slot);
    + result = pci_hp_register(hotplug_slot,
    + ctrl->pci_dev->subordinate,
    + slot->device);
    if (result) {
    err("pci_hp_register failed with error %d\n", result);
    goto error_name;
    diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
    index 996c942..405c608 100644
    --- a/drivers/pci/hotplug/fakephp.c
    +++ b/drivers/pci/hotplug/fakephp.c
    @@ -120,7 +120,7 @@ static int add_slot(struct pci_dev *dev)
    slot->release = &dummy_release;
    slot->private = dslot;

    - retval = pci_hp_register(slot);
    + retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn));
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_dslot;
    diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c
    index 600ed7b..eb7a1c0 100644
    --- a/drivers/pci/hotplug/ibmphp_ebda.c
    +++ b/drivers/pci/hotplug/ibmphp_ebda.c
    @@ -1000,7 +1000,8 @@ static int __init ebda_rsrc_controller (void)
    tmp_slot = list_entry (list, struct slot, ibm_slot_list);

    snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot));
    - pci_hp_register (tmp_slot->hotplug_slot);
    + pci_hp_register(tmp_slot->hotplug_slot,
    + pci_find_bus(0, tmp_slot->bus), tmp_slot->device);
    }

    print_ebda_hpc ();
    diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
    index 01c351c..9a259eb 100644
    --- a/drivers/pci/hotplug/pci_hotplug_core.c
    +++ b/drivers/pci/hotplug/pci_hotplug_core.c
    @@ -40,6 +40,7 @@
    #include
    #include
    #include
    +#include "../pci.h"

    #define MY_NAME "pci_hotplug"

    @@ -61,43 +62,6 @@ static int debug;

    static LIST_HEAD(pci_hotplug_slot_list);

    -struct kset pci_hotplug_slots_subsys;
    -
    -static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
    - struct attribute *attr, char *buf)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
    - return attribute->show ? attribute->show(slot, buf) : -EIO;
    -}
    -
    -static ssize_t hotplug_slot_attr_store(struct kobject *kobj,
    - struct attribute *attr, const char *buf, size_t len)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - struct hotplug_slot_attribute *attribute = to_hotplug_attr(attr);
    - return attribute->store ? attribute->store(slot, buf, len) : -EIO;
    -}
    -
    -static struct sysfs_ops hotplug_slot_sysfs_ops = {
    - .show = hotplug_slot_attr_show,
    - .store = hotplug_slot_attr_store,
    -};
    -
    -static void hotplug_slot_release(struct kobject *kobj)
    -{
    - struct hotplug_slot *slot = to_hotplug_slot(kobj);
    - if (slot->release)
    - slot->release(slot);
    -}
    -
    -static struct kobj_type hotplug_slot_ktype = {
    - .sysfs_ops = &hotplug_slot_sysfs_ops,
    - .release = &hotplug_slot_release,
    -};
    -
    -decl_subsys_name(pci_hotplug_slots, slots, &hotplug_slot_ktype, NULL);
    -
    /* these strings match up with the values in pci_bus_speed */
    static char *pci_bus_speed_strings[] = {
    "33 MHz PCI", /* 0x00 */
    @@ -151,16 +115,15 @@ GET_STATUS(power_status, u8)
    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)

    -static ssize_t power_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t power_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_power_status (slot, &value);
    + retval = get_power_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -168,9 +131,10 @@ exit:
    return retval;
    }

    -static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    unsigned long lpower;
    u8 power;
    int retval = 0;
    @@ -206,29 +170,30 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_power = {
    +static struct pci_slot_attribute hotplug_slot_attr_power = {
    .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .show = power_read_file,
    .store = power_write_file
    };

    -static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t attention_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_attention_status (slot, &value);
    + retval = get_attention_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    - retval = sprintf (buf, "%d\n", value);
    + retval = sprintf(buf, "%d\n", value);

    exit:
    return retval;
    }

    -static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t attention_write_file(struct pci_slot *slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot_ops *ops = slot->hotplug->ops;
    unsigned long lattention;
    u8 attention;
    int retval = 0;
    @@ -237,13 +202,13 @@ static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf,
    attention = (u8)(lattention & 0xff);
    dbg (" - attention = %d\n", attention);

    - if (!try_module_get(slot->ops->owner)) {
    + if (!try_module_get(ops->owner)) {
    retval = -ENODEV;
    goto exit;
    }
    - if (slot->ops->set_attention_status)
    - retval = slot->ops->set_attention_status(slot, attention);
    - module_put(slot->ops->owner);
    + if (ops->set_attention_status)
    + retval = ops->set_attention_status(slot->hotplug, attention);
    + module_put(ops->owner);

    exit:
    if (retval)
    @@ -251,18 +216,18 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_attention = {
    +static struct pci_slot_attribute hotplug_slot_attr_attention = {
    .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .show = attention_read_file,
    .store = attention_write_file
    };

    -static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t latch_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_latch_status (slot, &value);
    + retval = get_latch_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -271,17 +236,17 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_latch = {
    +static struct pci_slot_attribute hotplug_slot_attr_latch = {
    .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO},
    .show = latch_read_file,
    };

    -static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t presence_read_file(struct pci_slot *slot, char *buf)
    {
    int retval;
    u8 value;

    - retval = get_adapter_status (slot, &value);
    + retval = get_adapter_status(slot->hotplug, &value);
    if (retval)
    goto exit;
    retval = sprintf (buf, "%d\n", value);
    @@ -290,42 +255,20 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_presence = {
    +static struct pci_slot_attribute hotplug_slot_attr_presence = {
    .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO},
    .show = presence_read_file,
    };

    -static ssize_t address_read_file (struct hotplug_slot *slot, char *buf)
    -{
    - int retval;
    - u32 address;
    -
    - retval = get_address (slot, &address);
    - if (retval)
    - goto exit;
    - retval = sprintf (buf, "%04x:%02x:%02x\n",
    - (address >> 16) & 0xffff,
    - (address >> 8) & 0xff,
    - address & 0xff);
    -
    -exit:
    - return retval;
    -}
    -
    -static struct hotplug_slot_attribute hotplug_slot_attr_address = {
    - .attr = {.name = "address", .mode = S_IFREG | S_IRUGO},
    - .show = address_read_file,
    -};
    -
    static char *unknown_speed = "Unknown bus speed";

    -static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t max_bus_speed_read_file(struct pci_slot *slot, char *buf)
    {
    char *speed_string;
    int retval;
    enum pci_bus_speed value;

    - retval = get_max_bus_speed (slot, &value);
    + retval = get_max_bus_speed(slot->hotplug, &value);
    if (retval)
    goto exit;

    @@ -340,18 +283,18 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = {
    +static struct pci_slot_attribute hotplug_slot_attr_max_bus_speed = {
    .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO},
    .show = max_bus_speed_read_file,
    };

    -static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf)
    +static ssize_t cur_bus_speed_read_file(struct pci_slot *slot, char *buf)
    {
    char *speed_string;
    int retval;
    enum pci_bus_speed value;

    - retval = get_cur_bus_speed (slot, &value);
    + retval = get_cur_bus_speed(slot->hotplug, &value);
    if (retval)
    goto exit;

    @@ -366,14 +309,15 @@ exit:
    return retval;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = {
    +static struct pci_slot_attribute hotplug_slot_attr_cur_bus_speed = {
    .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO},
    .show = cur_bus_speed_read_file,
    };

    -static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf,
    +static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
    size_t count)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    unsigned long ltest;
    u32 test;
    int retval = 0;
    @@ -396,13 +340,14 @@ exit:
    return count;
    }

    -static struct hotplug_slot_attribute hotplug_slot_attr_test = {
    +static struct pci_slot_attribute hotplug_slot_attr_test = {
    .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR},
    .store = test_write_file
    };

    -static int has_power_file (struct hotplug_slot *slot)
    +static int has_power_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if ((slot->ops->enable_slot) ||
    @@ -412,8 +357,9 @@ static int has_power_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_attention_file (struct hotplug_slot *slot)
    +static int has_attention_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if ((slot->ops->set_attention_status) ||
    @@ -422,8 +368,9 @@ static int has_attention_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_latch_file (struct hotplug_slot *slot)
    +static int has_latch_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_latch_status)
    @@ -431,8 +378,9 @@ static int has_latch_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_adapter_file (struct hotplug_slot *slot)
    +static int has_adapter_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_adapter_status)
    @@ -440,17 +388,9 @@ static int has_adapter_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_address_file (struct hotplug_slot *slot)
    -{
    - if ((!slot) || (!slot->ops))
    - return -ENODEV;
    - if (slot->ops->get_address)
    - return 0;
    - return -ENOENT;
    -}
    -
    -static int has_max_bus_speed_file (struct hotplug_slot *slot)
    +static int has_max_bus_speed_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_max_bus_speed)
    @@ -458,8 +398,9 @@ static int has_max_bus_speed_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_cur_bus_speed_file (struct hotplug_slot *slot)
    +static int has_cur_bus_speed_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->get_cur_bus_speed)
    @@ -467,8 +408,9 @@ static int has_cur_bus_speed_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int has_test_file (struct hotplug_slot *slot)
    +static int has_test_file(struct pci_slot *pci_slot)
    {
    + struct hotplug_slot *slot = pci_slot->hotplug;
    if ((!slot) || (!slot->ops))
    return -ENODEV;
    if (slot->ops->hardware_test)
    @@ -476,7 +418,7 @@ static int has_test_file (struct hotplug_slot *slot)
    return -ENOENT;
    }

    -static int fs_add_slot (struct hotplug_slot *slot)
    +static int fs_add_slot(struct pci_slot *slot)
    {
    int retval = 0;

    @@ -507,13 +449,6 @@ static int fs_add_slot (struct hotplug_slot *slot)
    goto exit_adapter;
    }

    - if (has_address_file(slot) == 0) {
    - retval = sysfs_create_file(&slot->kobj,
    - &hotplug_slot_attr_address.attr);
    - if (retval)
    - goto exit_address;
    - }
    -
    if (has_max_bus_speed_file(slot) == 0) {
    retval = sysfs_create_file(&slot->kobj,
    &hotplug_slot_attr_max_bus_speed.attr);
    @@ -546,10 +481,6 @@ exit_cur_speed:
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);

    exit_max_speed:
    - if (has_address_file(slot) == 0)
    - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
    -
    -exit_address:
    if (has_adapter_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);

    @@ -569,7 +500,7 @@ exit:
    return retval;
    }

    -static void fs_remove_slot (struct hotplug_slot *slot)
    +static void fs_remove_slot(struct pci_slot *slot)
    {
    if (has_power_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
    @@ -583,9 +514,6 @@ static void fs_remove_slot (struct hotplug_slot *slot)
    if (has_adapter_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);

    - if (has_address_file(slot) == 0)
    - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
    -
    if (has_max_bus_speed_file(slot) == 0)
    sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);

    @@ -609,6 +537,12 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
    return NULL;
    }

    +static void hotplug_release(struct pci_slot *slot)
    +{
    + struct hotplug_slot *hotplug = slot->hotplug;
    + hotplug->release(hotplug);
    +}
    +
    /**
    * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem
    * @slot: pointer to the &struct hotplug_slot to register
    @@ -618,9 +552,10 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int pci_hp_register (struct hotplug_slot *slot)
    +int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr)
    {
    int result;
    + struct pci_slot *pci_slot;

    if (slot == NULL)
    return -ENODEV;
    @@ -632,19 +567,23 @@ int pci_hp_register (struct hotplug_slot *slot)
    return -EINVAL;
    }

    - kobject_set_name(&slot->kobj, "%s", slot->name);
    - kobj_set_kset_s(slot, pci_hotplug_slots_subsys);
    + pci_slot = pci_create_slot(bus, slot_nr, slot->name);
    + if (IS_ERR(pci_slot))
    + return PTR_ERR(pci_slot);

    - /* this can fail if we have already registered a slot with the same name */
    - if (kobject_register(&slot->kobj)) {
    - err("Unable to register kobject");
    - return -EINVAL;
    + result = pci_slot_add_hotplug(bus, slot_nr, hotplug_release);
    + if (result) {
    + pci_destroy_slot(pci_slot);
    + return result;
    }
    -
    - list_add (&slot->slot_list, &pci_hotplug_slot_list);

    - result = fs_add_slot (slot);
    - dbg ("Added slot %s to the list\n", slot->name);
    + slot->pci_slot = pci_slot;
    + pci_slot->hotplug = slot;
    +
    + list_add(&slot->slot_list, &pci_hotplug_slot_list);
    +
    + result = fs_add_slot(pci_slot);
    + dbg("Added slot %s to the list\n", slot->name);
    return result;
    }

    @@ -657,22 +596,24 @@ int pci_hp_register (struct hotplug_slot *slot)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int pci_hp_deregister (struct hotplug_slot *slot)
    +int pci_hp_deregister(struct hotplug_slot *hotplug)
    {
    struct hotplug_slot *temp;
    + struct pci_slot *slot;

    - if (slot == NULL)
    + if (!hotplug)
    return -ENODEV;

    - temp = get_slot_from_name (slot->name);
    - if (temp != slot) {
    + temp = get_slot_from_name(hotplug->name);
    + if (temp != hotplug)
    return -ENODEV;
    - }
    - list_del (&slot->slot_list);

    - fs_remove_slot (slot);
    - dbg ("Removed slot %s from the list\n", slot->name);
    - kobject_unregister(&slot->kobj);
    + list_del(&hotplug->slot_list);
    +
    + slot = hotplug->pci_slot;
    + fs_remove_slot(slot);
    + pci_destroy_slot(slot);
    + dbg("Removed slot %s from the list\n", hotplug->name);
    return 0;
    }

    @@ -686,13 +627,15 @@ int pci_hp_deregister (struct hotplug_slot *slot)
    *
    * Returns 0 if successful, anything else for an error.
    */
    -int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
    +int __must_check pci_hp_change_slot_info(struct hotplug_slot *hotplug,
    struct hotplug_slot_info *info)
    {
    - if ((slot == NULL) || (info == NULL))
    + struct pci_slot *slot;
    + if (!hotplug || !info)
    return -ENODEV;
    + slot = hotplug->pci_slot;

    - memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
    + memcpy(hotplug->info, info, sizeof(struct hotplug_slot_info));

    return 0;
    }
    @@ -701,31 +644,21 @@ static int __init pci_hotplug_init (void)
    {
    int result;

    - kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
    - result = subsystem_register(&pci_hotplug_slots_subsys);
    - if (result) {
    - err("Register subsys with error %d\n", result);
    - goto exit;
    - }
    result = cpci_hotplug_init(debug);
    if (result) {
    err ("cpci_hotplug_init with error %d\n", result);
    - goto err_subsys;
    + goto err_cpci;
    }

    info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
    - goto exit;
    -
    -err_subsys:
    - subsystem_unregister(&pci_hotplug_slots_subsys);
    -exit:
    +
    +err_cpci:
    return result;
    }

    static void __exit pci_hotplug_exit (void)
    {
    cpci_hotplug_exit();
    - subsystem_unregister(&pci_hotplug_slots_subsys);
    }

    module_init(pci_hotplug_init);
    @@ -737,7 +670,6 @@ MODULE_LICENSE("GPL");
    module_param(debug, bool, 0644);
    MODULE_PARM_DESC(debug, "Debugging mode enabled or not");

    -EXPORT_SYMBOL_GPL(pci_hotplug_slots_subsys);
    EXPORT_SYMBOL_GPL(pci_hp_register);
    EXPORT_SYMBOL_GPL(pci_hp_deregister);
    EXPORT_SYMBOL_GPL(pci_hp_change_slot_info);
    diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
    index 6462ac3..0e9eaf6 100644
    --- a/drivers/pci/hotplug/pciehp_core.c
    +++ b/drivers/pci/hotplug/pciehp_core.c
    @@ -69,7 +69,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
    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 *slot, enum pci_bus_speed *value);
    static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);

    @@ -82,7 +81,6 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
    .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,
    };
    @@ -245,14 +243,18 @@ static int init_slots(struct controller *ctrl)
    dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
    "slot_device_offset=%x\n", slot->bus, slot->device,
    slot->hp_slot, slot->number, ctrl->slot_device_offset);
    - retval = pci_hp_register(hotplug_slot);
    + retval = pci_hp_register(hotplug_slot,
    + ctrl->pci_dev->subordinate,
    + slot->device);
    + if (retval == -EBUSY)
    + goto error_info;
    if (retval) {
    err ("pci_hp_register failed with error %d\n", retval);
    goto error_info;
    }
    /* create additional sysfs entries */
    if (EMI(ctrl->ctrlcap)) {
    - retval = sysfs_create_file(&hotplug_slot->kobj,
    + retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj,
    &hotplug_slot_attr_lock.attr);
    if (retval) {
    pci_hp_deregister(hotplug_slot);
    @@ -285,7 +287,7 @@ static void cleanup_slots(struct controller *ctrl)
    slot = list_entry(tmp, struct slot, slot_list);
    list_del(&slot->slot_list);
    if (EMI(ctrl->ctrlcap))
    - sysfs_remove_file(&slot->hotplug_slot->kobj,
    + sysfs_remove_file(&slot->hotplug_slot->pci_slot->kobj,
    &hotplug_slot_attr_lock.attr);
    cancel_delayed_work(&slot->work);
    flush_scheduled_work();
    @@ -387,18 +389,6 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = hotplug_slot->private;
    - struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
    -
    - return 0;
    -}
    -
    static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
    {
    struct slot *slot = hotplug_slot->private;
    @@ -464,7 +454,12 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
    /* Setup the slot information structures */
    rc = init_slots(ctrl);
    if (rc) {
    - err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
    + if (rc == -EBUSY)
    + warn("%s: slot already registered by another "
    + "hotplug driver\n", PCIE_MODULE_NAME);
    + else
    + err("%s: slot initialization failed\n",
    + PCIE_MODULE_NAME);
    goto err_out_release_ctlr;
    }

    diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
    index a080fed..3663507 100644
    --- a/drivers/pci/hotplug/rpadlpar_sysfs.c
    +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
    @@ -23,6 +23,8 @@

    #define MAX_DRC_NAME_LEN 64

    +extern struct kset pci_slots_subsys;
    +
    /* Store return code of dlpar operation in attribute struct */
    struct dlpar_io_attr {
    int rc;
    @@ -130,7 +132,7 @@ struct kobj_type ktype_dlpar_io = {

    struct kset dlpar_io_kset = {
    .kobj = {.ktype = &ktype_dlpar_io,
    - .parent = &pci_hotplug_slots_subsys.kobj},
    + .parent = &pci_slots_subsys.kobj},
    .ktype = &ktype_dlpar_io,
    };

    diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
    index d4ee872..3e1f24b 100644
    --- a/drivers/pci/hotplug/rpaphp_slot.c
    +++ b/drivers/pci/hotplug/rpaphp_slot.c
    @@ -160,7 +160,8 @@ int rpaphp_register_slot(struct slot *slot)
    return -EAGAIN;
    }

    - retval = pci_hp_register(php_slot);
    + retval = pci_hp_register(php_slot, slot->bus,
    + PCI_SLOT(PCI_DN(slot->dn->child)->devfn));
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    return retval;
    diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
    index 693519e..cc74602 100644
    --- a/drivers/pci/hotplug/sgi_hotplug.c
    +++ b/drivers/pci/hotplug/sgi_hotplug.c
    @@ -625,7 +625,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
    bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
    bss_hotplug_slot->release = &sn_release_slot;

    - rc = pci_hp_register(bss_hotplug_slot);
    + rc = pci_hp_register(bss_hotplug_slot, pci_bus, device);
    if (rc)
    goto register_err;
    }
    diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
    index 80dec97..22c4d2e 100644
    --- a/drivers/pci/hotplug/shpchp_core.c
    +++ b/drivers/pci/hotplug/shpchp_core.c
    @@ -65,7 +65,6 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
    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 *slot, enum pci_bus_speed *value);
    static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);

    @@ -78,7 +77,6 @@ static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
    .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,
    };
    @@ -152,7 +150,8 @@ static int init_slots(struct controller *ctrl)
    dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
    "slot_device_offset=%x\n", slot->bus, slot->device,
    slot->hp_slot, slot->number, ctrl->slot_device_offset);
    - retval = pci_hp_register(slot->hotplug_slot);
    + retval = pci_hp_register(slot->hotplug_slot,
    + ctrl->pci_dev->subordinate, slot->device);
    if (retval) {
    err("pci_hp_register failed with error %d\n", retval);
    goto error_info;
    @@ -277,18 +276,6 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
    return 0;
    }

    -static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
    -{
    - struct slot *slot = get_slot(hotplug_slot);
    - struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
    -
    - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
    -
    - *value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
    -
    - return 0;
    -}
    -
    static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
    {
    struct slot *slot = get_slot(hotplug_slot);
    diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
    index fc87e14..4bcfabf 100644
    --- a/drivers/pci/pci.h
    +++ b/drivers/pci/pci.h
    @@ -91,3 +91,16 @@ pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
    }

    struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
    +
    +/* PCI slot sysfs helper code */
    +#define to_pci_slot(s) container_of(s, struct pci_slot, kobj)
    +
    +extern struct kset pci_slots_subsys;
    +
    +struct pci_slot_attribute {
    + struct attribute attr;
    + ssize_t (*show)(struct pci_slot *, char *);
    + ssize_t (*store)(struct pci_slot *, const char *, size_t);
    +};
    +#define to_pci_slot_attr(s) container_of(s, struct pci_slot_attribute, attr)
    +
    diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c
    new file mode 100644
    index 0000000..f16e0af
    --- /dev/null
    +++ b/drivers/pci/slot.c
    @@ -0,0 +1,197 @@
    +/*
    + * drivers/pci/slot.c
    + * Copyright (C) 2006 Matthew Wilcox
    + * Copyright (C) 2006,2007 Hewlett-Packard Development Company, L.P.
    + * Copyright (C) 2007 Alex Chiang
    + */
    +
    +#include
    +#include
    +#include "pci.h"
    +
    +struct kset pci_slots_subsys;
    +EXPORT_SYMBOL_GPL(pci_slots_subsys);
    +
    +static ssize_t pci_slot_attr_show(struct kobject *kobj,
    + struct attribute *attr, char *buf)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
    + return attribute->show ? attribute->show(slot, buf) : -EIO;
    +}
    +
    +static ssize_t pci_slot_attr_store(struct kobject *kobj,
    + struct attribute *attr, const char *buf, size_t len)
    +{
    + struct pci_slot *slot = to_pci_slot(kobj);
    + struct pci_slot_attribute *attribute = to_pci_slot_attr(attr);
    + return attribute->store ? attribute->store(slot, buf, len) : -EIO;
    +}
    +
    +static struct sysfs_ops pci_slot_sysfs_ops = {
    + .show = pci_slot_attr_show,
    + .store = pci_slot_attr_store,
    +};
    +
    +static ssize_t address_read_file(struct pci_slot *slot, char *buf)
    +{
    + return sprintf(buf, "%04x:%02x:%02x\n", pci_domain_nr(slot->bus),
    + slot->bus->number, slot->number);
    +}
    +
    +static struct pci_slot_attribute pci_slot_attr_address = {
    + .attr = { .name = "address", .mode = S_IFREG | S_IRUGO },
    + .show = address_read_file,
    +};
    +
    +static void remove_sysfs_files(struct pci_slot *slot)
    +{
    + sysfs_remove_file(&slot->kobj, &pci_slot_attr_address.attr);
    +}
    +
    +static int create_sysfs_files(struct pci_slot *slot)
    +{
    + int result;
    +
    + result = sysfs_create_file(&slot->kobj, &pci_slot_attr_address.attr);
    +
    + return result;
    +}
    +
    +static void pci_slot_release(struct kobject *kobj)
    +{
    + struct pci_slot **pprev;
    + struct pci_slot *slot = to_pci_slot(kobj);
    +
    + for (pprev = &slot->bus->slot; *pprev; pprev = &(*pprev)->next) {
    + if (*pprev == slot) {
    + *pprev = slot->next;
    + break;
    + }
    + }
    +
    + if (slot->release)
    + slot->release(slot);
    +
    + remove_sysfs_files(slot);
    + kfree(slot);
    +}
    +
    +static struct kobj_type pci_slot_ktype = {
    + .sysfs_ops = &pci_slot_sysfs_ops,
    + .release = &pci_slot_release,
    +};
    +decl_subsys_name(pci_slots, slots, &pci_slot_ktype, NULL);
    +
    +int pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    + void (*release)(struct pci_slot *))
    +{
    + struct pci_slot *slot;
    + int retval, found;
    +
    + retval = found = 0;
    +
    + down_write(&pci_bus_sem);
    +
    + /* This slot should have already been created, so look for it. If
    + * we can't find it, return -EEXIST.
    + */
    + for (slot = parent->slot; slot; slot = slot->next)
    + if (slot->number == slot_nr) {
    + found = 1;
    + break;
    + }
    +
    + if (!found) {
    + retval = -EEXIST;
    + goto out;
    + }
    +
    + if (slot->release) {
    + retval = -EBUSY;
    + goto out;
    + }
    +
    + slot->release = release;
    + out:
    + up_write(&pci_bus_sem);
    + return retval;
    +}
    +EXPORT_SYMBOL_GPL(pci_slot_add_hotplug);
    +
    +struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
    + const char *name)
    +{
    + struct pci_slot *slot;
    + int err;
    +
    + down_write(&pci_bus_sem);
    +
    + /* If we've already created this slot, bump refcount and return. */
    + for (slot = parent->slot; slot; slot = slot->next) {
    + if (slot->number == slot_nr) {
    + kobject_get(&slot->kobj);
    + goto out;
    + }
    + }
    +
    + slot = kzalloc(sizeof(*slot), GFP_KERNEL);
    + if (!slot) {
    + slot = ERR_PTR(-ENOMEM);
    + goto out;
    + }
    +
    + slot->bus = parent;
    + slot->number = slot_nr;
    +
    + kobject_set_name(&slot->kobj, "%s", name);
    + kobj_set_kset_s(slot, pci_slots_subsys);
    + if (kobject_register(&slot->kobj)) {
    + printk(KERN_ERR "Unable to register kobject %s", name);
    + err = -EINVAL;
    + goto err;
    + }
    +
    + err = create_sysfs_files(slot);
    + if (err)
    + goto unregister;
    +
    + slot->next = parent->slot;
    + parent->slot = slot;
    +
    + out:
    + up_write(&pci_bus_sem);
    + return slot;
    +
    + unregister:
    + kobject_unregister(&slot->kobj);
    + err:
    + kfree(slot);
    + slot = ERR_PTR(err);
    + goto out;
    +}
    +EXPORT_SYMBOL_GPL(pci_create_slot);
    +
    +int pci_destroy_slot(struct pci_slot *slot)
    +{
    + kobject_put(&slot->kobj);
    + if (atomic_read(&slot->kobj.kref.refcount) == 1)
    + kobject_unregister(&slot->kobj);
    +
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(pci_destroy_slot);
    +
    +static int pci_slot_init(void)
    +{
    + int result;
    +
    + kobj_set_kset_s(&pci_slots_subsys, pci_bus_type.subsys);
    + result = subsystem_register(&pci_slots_subsys);
    + if (result)
    + printk(KERN_ERR "PCI: Slot initialisation failure (%d)",
    + result);
    + return result;
    +}
    +
    +subsys_initcall(pci_slot_init);
    diff --git a/include/linux/pci.h b/include/linux/pci.h
    index 0dd93bb..b70d7dc 100644
    --- a/include/linux/pci.h
    +++ b/include/linux/pci.h
    @@ -129,6 +129,16 @@ struct pci_cap_saved_state {
    u32 data[0];
    };

    +/* pci_slot represents a physical slot */
    +struct pci_slot {
    + struct pci_bus *bus; /* The bus this slot is on */
    + struct pci_slot *next; /* Next slot on this bus */
    + struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */
    + unsigned char number; /* PCI_SLOT(pci_dev->devfn) */
    + struct kobject kobj;
    + void (*release)(struct pci_slot *);
    +};
    +
    /*
    * The pci_dev structure is used to describe PCI devices.
    */
    @@ -140,6 +150,7 @@ struct pci_dev {

    void *sysdata; /* hook for sys-specific extension */
    struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
    + struct pci_slot *slot; /* Physical slot this device is in */

    unsigned int devfn; /* encoded device & function index */
    unsigned short vendor;
    @@ -261,6 +272,7 @@ struct pci_bus {
    struct list_head children; /* list of child buses */
    struct list_head devices; /* list of devices on this bus */
    struct pci_dev *self; /* bridge device as seen by parent */
    + struct pci_slot *slot; /* First physical slot on this bus */
    struct resource *resource[PCI_BUS_NUM_RESOURCES];
    /* address space routed to this bus */

    @@ -470,6 +482,11 @@ static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *s
    }
    struct pci_bus *pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
    struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
    +struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
    + const char *name);
    +int pci_slot_add_hotplug(struct pci_bus *parent, int slot_nr,
    + void (*release)(struct pci_slot *));
    +int pci_destroy_slot(struct pci_slot *slot);
    int pci_scan_slot(struct pci_bus *bus, int devfn);
    struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
    void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
    diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
    index ab4cb6e..bb36c59 100644
    --- a/include/linux/pci_hotplug.h
    +++ b/include/linux/pci_hotplug.h
    @@ -95,9 +95,6 @@ struct hotplug_slot_attribute {
    * @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.
    @@ -120,7 +117,6 @@ struct hotplug_slot_ops {
    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);
    };
    @@ -140,7 +136,6 @@ struct hotplug_slot_info {
    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;
    };
    @@ -166,15 +161,14 @@ struct hotplug_slot {

    /* Variables below this are for use only by the hotplug pci core. */
    struct list_head slot_list;
    - struct kobject kobj;
    + struct pci_slot *pci_slot;
    };
    #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)

    -extern int pci_hp_register (struct hotplug_slot *slot);
    -extern int pci_hp_deregister (struct hotplug_slot *slot);
    +extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr);
    +extern int pci_hp_deregister(struct hotplug_slot *slot);
    extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
    struct hotplug_slot_info *info);
    -extern struct kset pci_hotplug_slots_subsys;

    /* PCI Setting Record (Type 0) */
    struct hpp_type0 {
    --
    1.5.3.1.g1e61

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

  20. Re: [PATCH 0/4, v3] Physical PCI slot objects

    On Mon, Nov 26, 2007 at 03:22:53PM -0700, Alex Chiang wrote:
    > Hi Gary, Kenji-san, et. al,
    >
    > * Gary Hade :
    > >
    > > Alex, What I was trying to suggest is a boot-time kernel
    > > option, not a kernel configuration option. The basic idea is
    > > to give the user (with a single binary kernel) the ability to
    > > include your ACPI-PCI slot driver feature changes only when
    > > they are really needed. In addition to reducing the number of
    > > system/PCI hotplug driver combinations where your changes would
    > > need to be validated, I believe would also help alleviate other
    > > worries (e.g. Andi Kleen's memory consumption concern). I
    > > believe this goal could also be achieved with the kernel config
    > > option by making the pci_slot module runtime loadable with the
    > > PCI hotplug drivers only visiting your new code when the
    > > pci_slot driver is loaded, although I think this would be more
    > > difficult to implement.

    >
    > I have modified my patch series so that the final patch that
    > introduces my ACPI-PCI slot driver is a full-fledged module, that
    > has a tristate Kconfig option.
    >
    > It can be modprobe'd/rmmod'ed in any combination, and in any
    > order with other PCI hotplug modules. There is no ordering
    > dependency, even at module unload time, so you can safely rmmod
    > pci_slot, and safely continue using features provided by the PCI
    > hotplug drivers (acpiphp, pciehp, etc.). The opposite works too.


    Nice! I like the loadable module approach much better than my
    boot-time kernel option suggestion.

    >
    > The one limitation is that two separate hotplug drivers cannot
    > both claim the same device (2nd module loaded will get -EBUSY
    > errors), but I do not believe that is a regression from current
    > behavior.


    I cannot confirm this since the systems I am using only support
    a single hotplug driver (acpiphp).

    >
    > I have only tested with acpiphp and pciehp, as that's the only
    > hardware I have, but I believe my code will play nicely with the
    > other PCI hp drivers as well.


    I have only tested your changes with acpiphp.

    >
    > The patch series is fully bisectable, and the correct behavior
    > occurs no matter which patch you happen to have applied.


    Based on my testing (see below) this appears to be true.

    >
    > I'll be sending v5 of patches 3 and 4 shortly (patches 1 and 2
    > did not change). It is still based on 2.6.24-rc2, because I was
    > too scared to do another git rebase while using stgit. :-/


    I have been using 2.6.24-rc3 source for my testing.

    >
    > > Also, I notice that even with your current CONFIG_ACPI_PCI_SLOT
    > > implementation your numerous PCI hotplug driver changes (except
    > > for only two places in pci_hotplug_core.c where there is
    > > `#ifndef CONFIG_ACPI_PCI_SLOT` and `#ifdef CONFIG_ACPI_PCI_SLOT`)
    > > are _always_ exposed. So, even with CONFIG_ACPI_PCI_SLOT disabled
    > > there is IMO a need for testing of the affected PCI hotplug drivers
    > > on more than a small number of isolated systems.

    >
    > You are, of course, correct.
    >
    > In my opinion, though, I would say most of the changes to the PCI
    > hotplug drivers themselves are pretty straightforward, as in
    > removing the different ways of getting the PCI address.
    >
    > The scary part of the changes (aside from the ACPI-PCI slot
    > driver) revolve around the new struct pci_slot, which is
    > relatively self-contained, and only expose themselves via the
    > pci_create_slot/pci_destroy_slot interfaces which only the PCI
    > hotplug corecares about.


    I think this sounds like a reasonable argument for not
    doing what I was trying to suggest.

    >
    > Regardless, your point stands. How do you suggest I get more
    > testing time?


    I am only able to test with acpiphp. In addition to the
    testing on the x3850 described below I would also like to
    do some testing on an x3950 which has a mix of hotplug and
    non-hotplug slots. If this testing which I hope to complete
    this week goes well, I will be satisfied.

    I will let others speak for the other hotplug drivers
    and platforms.

    > Is this patchset appropriate for the -mm tree yet?


    I would defer to our illustrious maintainers on this one.

    > Or do you think it still needs more work?


    I am now much more comfortable with your changes with respect
    to acpiphp on the systems I worry about but others may have
    concerns with respect to the other hotplug drivers, or even
    acpiphp, on other systems.

    >
    > > The good news is that I was able to test your v3 changes
    > > (w/2.6.24-rc3 source) on our x3850 today with 'acpiphp' and,
    > > except for the above mentioned inability to run-time
    > > include/exclude them, they seemed to work fine. The previous
    > > boot-time ACPI error messages are gone and I was able to
    > > successfully hot-remove and hot-add both PCI-X and PCIe
    > > adapters.

    >
    > Thanks for testing. Please let me know how v5 works for you too.


    I just tried your v5 (1/4 v3, 2/4 v3, 3/4 v5, 4/4 v5) applied
    to 2.6.24-rc3 source with acpiphp on the x3850 and found
    nothing to complain about. About time, eh?

    Following boot, 'pci_slot' was already loaded and slot directories
    (each containing an address file) for all 6 (2 PCI-X, 4 PCIe)
    slots were present. I then successfully modprobed acpiphp and
    successfully hot-removed the PCI-X and PCIe cards that were present
    during boot. I then successfully hot-added the same cards to
    the slots they occupied during boot and to slots that were vacant
    during boot.

    I then unloaded acpiphp and pci_slot and reloaded both in
    the opposite order (acpiphp 1st, pci_slot 2nd) and
    successfully repeated the above hot-remove/hot-add operations.

    I then unloaded both drivers again, reloaded only acpiphp,
    and successfully repeated the same hot-remove/hot-add operations.

    I will let you know how it goes on the x3950.

    Thanks for all your hard work on this.

    Gary

    --
    Gary Hade
    System x Enablement
    IBM Linux Technology Center
    503-578-4503 IBM T/L: 775-4503
    garyhade@us.ibm.com
    http://www.ibm.com/linux/ltc

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

+ Reply to Thread
Page 1 of 2 1 2 LastLast