--- drivers/pci/hotplug/pci_hotplug_core.c | 6 - drivers/pci/probe.c | 1 drivers/pci/slot.c | 147 +++++++++++++++++++++++++++------ include/linux/pci.h | 10 +- include/linux/pci_hotplug.h | 12 +- 5 files changed, 141 insertions(+), 35 deletions(-) Index: linux-2.6/drivers/pci/hotplug/pci_hotplug_core.c =================================================================== --- linux-2.6.orig/drivers/pci/hotplug/pci_hotplug_core.c +++ linux-2.6/drivers/pci/hotplug/pci_hotplug_core.c @@ -431,8 +431,8 @@ static struct hotplug_slot *get_slot_fro * * Returns 0 if successful, anything else for an error. */ -int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, - int devnr, const char *name, +int __pci_hp_register(struct hotplug_slot *slot, struct pci_dev *b_dev, + struct pci_bus *bus, int devnr, const char *name, struct module *owner, const char *mod_name) { int result; @@ -457,7 +457,7 @@ int __pci_hp_register(struct hotplug_slo * 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, devnr, name, slot); + pci_slot = __pci_create_slot(b_dev, bus, devnr, name, slot); if (IS_ERR(pci_slot)) { result = PTR_ERR(pci_slot); goto out; Index: linux-2.6/drivers/pci/probe.c =================================================================== --- linux-2.6.orig/drivers/pci/probe.c +++ linux-2.6/drivers/pci/probe.c @@ -1454,6 +1454,7 @@ struct pci_dev *alloc_pci_dev(void) INIT_LIST_HEAD(&dev->bus_list); INIT_LIST_HEAD(&dev->addon_resources); + INIT_LIST_HEAD(&dev->slots); return dev; } Index: linux-2.6/drivers/pci/slot.c =================================================================== --- linux-2.6.orig/drivers/pci/slot.c +++ linux-2.6/drivers/pci/slot.c @@ -38,14 +38,24 @@ static const struct sysfs_ops pci_slot_s static ssize_t address_read_file(struct pci_slot *slot, char *buf) { + struct pci_bus *bus; + + if (slot->b_dev) + bus = slot->b_dev->subordinate; + else + bus = slot->bus; + + if (!bus) + return sprintf(buf, "none\n"); + if (slot->number == 0xff) return sprintf(buf, "%04x:%02x\n", - pci_domain_nr(slot->bus), - slot->bus->number); + pci_domain_nr(bus), + bus->number); else return sprintf(buf, "%04x:%02x:%02x\n", - pci_domain_nr(slot->bus), - slot->bus->number, + pci_domain_nr(bus), + bus->number, slot->number); } @@ -90,25 +100,67 @@ static ssize_t bus_speed_read(enum pci_b static ssize_t max_speed_read_file(struct pci_slot *slot, char *buf) { - return bus_speed_read(slot->bus->max_bus_speed, buf); + struct pci_bus *bus; + enum pci_bus_speed speed; + + if (slot->b_dev) + bus = slot->b_dev->subordinate; + else + bus = slot->bus; + + if (!bus) + speed = ARRAY_SIZE(pci_bus_speed_strings); + else + speed = bus->max_bus_speed; + + return bus_speed_read(speed, buf); } static ssize_t cur_speed_read_file(struct pci_slot *slot, char *buf) { - return bus_speed_read(slot->bus->cur_bus_speed, buf); + struct pci_bus *bus; + enum pci_bus_speed speed; + + if (slot->b_dev) + bus = slot->b_dev->subordinate; + else + bus = slot->bus; + + if (!bus) + speed = ARRAY_SIZE(pci_bus_speed_strings); + else + speed = bus->cur_bus_speed; + + return bus_speed_read(speed, buf); } static void pci_slot_release(struct kobject *kobj) { - struct pci_dev *dev; struct pci_slot *slot = to_pci_slot(kobj); + struct pci_dev *b_dev = slot->b_dev; + struct pci_bus *bus; + struct device *device; + + if (b_dev) { + bus = b_dev->subordinate; + if (bus) + device = &bus->dev; + else + device = &b_dev->dev; + } else { + bus = slot->bus; + device = &bus->dev; + } - dev_dbg(&slot->bus->dev, "dev %02x, released physical slot %s\n", + dev_dbg(device, "dev %02x, released physical slot %s\n", slot->number, pci_slot_name(slot)); - list_for_each_entry(dev, &slot->bus->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot->number) - dev->slot = NULL; + if (bus) { + struct pci_dev *dev; + list_for_each_entry(dev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot->number) + dev->slot = NULL; + } list_del(&slot->list); @@ -191,13 +243,20 @@ static int rename_slot(struct pci_slot * return result; } -static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) +static struct pci_slot *get_slot(struct pci_dev *b_dev, + struct pci_bus *parent, int slot_nr) { struct pci_slot *slot; + struct list_head *slots; /* * We already hold pci_bus_sem so don't worry */ - list_for_each_entry(slot, &parent->slots, list) + if (b_dev) + slots = &b_dev->slots; + else + slots = &parent->slots; + + list_for_each_entry(slot, slots, list) if (slot->number == slot_nr) { kobject_get(&slot->kobj); return slot; @@ -244,14 +303,16 @@ static struct pci_slot *get_slot(struct * %struct pci_bus and bb is the bus number. In other words, the devfn of * the 'placeholder' slot will not be displayed. */ -struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, - const char *name, +struct pci_slot *__pci_create_slot(struct pci_dev *b_dev, + struct pci_bus *parent, + int slot_nr, const char *name, struct hotplug_slot *hotplug) { - struct pci_dev *dev; + struct pci_bus *bus; struct pci_slot *slot; int err = 0; char *slot_name = NULL; + struct device *device; down_write(&pci_bus_sem); @@ -262,7 +323,7 @@ struct pci_slot *pci_create_slot(struct * Hotplug drivers are allowed to rename an existing slot, * but only if not already claimed. */ - slot = get_slot(parent, slot_nr); + slot = get_slot(b_dev, parent, slot_nr); if (slot) { if (hotplug) { if ((err = slot->hotplug ? -EBUSY : 0) @@ -282,6 +343,7 @@ placeholder: goto err; } + slot->b_dev = b_dev; slot->bus = parent; slot->number = slot_nr; @@ -299,14 +361,28 @@ placeholder: goto err; INIT_LIST_HEAD(&slot->list); - list_add(&slot->list, &parent->slots); - - list_for_each_entry(dev, &parent->devices, bus_list) - if (PCI_SLOT(dev->devfn) == slot_nr) - dev->slot = slot; + if (b_dev) { + list_add(&slot->list, &b_dev->slots); + bus = b_dev->subordinate; + if (bus) + device = &bus->dev; + else + device = &b_dev->dev; + } + else { + list_add(&slot->list, &parent->slots); + bus = parent; + device = &bus->dev; + } - dev_dbg(&parent->dev, "dev %02x, created physical slot %s\n", + dev_dbg(device, "dev %02x, created physical slot %s\n", slot_nr, pci_slot_name(slot)); + if (bus) { + struct pci_dev *dev; + list_for_each_entry(dev, &bus->devices, bus_list) + if (PCI_SLOT(dev->devfn) == slot_nr) + dev->slot = slot; + } out: kfree(slot_name); @@ -317,6 +393,13 @@ err: slot = ERR_PTR(err); goto out; } +EXPORT_SYMBOL_GPL(__pci_create_slot); +struct pci_slot *pci_create_slot(struct pci_bus *parent, + int slot_nr, const char *name, + struct hotplug_slot *hotplug) +{ + return __pci_create_slot(NULL, parent, slot_nr, name, hotplug); +} EXPORT_SYMBOL_GPL(pci_create_slot); /** @@ -331,14 +414,19 @@ EXPORT_SYMBOL_GPL(pci_create_slot); void pci_renumber_slot(struct pci_slot *slot, int slot_nr) { struct pci_slot *tmp; + struct list_head *slots; down_write(&pci_bus_sem); - list_for_each_entry(tmp, &slot->bus->slots, list) { + if (slot->b_dev) + slots = &slot->b_dev->slots; + else + slots = &slot->bus->slots; + + list_for_each_entry(tmp, slots, list) { WARN_ON(tmp->number == slot_nr); goto out; } - slot->number = slot_nr; out: up_write(&pci_bus_sem); @@ -355,7 +443,14 @@ EXPORT_SYMBOL_GPL(pci_renumber_slot); */ void pci_destroy_slot(struct pci_slot *slot) { - dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n", + struct device *dev; + + if (slot->b_dev) + dev = &slot->b_dev->dev; + else + dev = &slot->bus->dev; + + dev_dbg(dev, "dev %02x, dec refcount to %d\n", slot->number, atomic_read(&slot->kobj.kref.refcount) - 1); down_write(&pci_bus_sem); Index: linux-2.6/include/linux/pci.h =================================================================== --- linux-2.6.orig/include/linux/pci.h +++ linux-2.6/include/linux/pci.h @@ -59,6 +59,7 @@ /* pci_slot represents a physical slot */ struct pci_slot { + struct pci_dev *b_dev; /* the bridge this slot is under */ struct pci_bus *bus; /* The bus this slot is on */ struct list_head list; /* node in list of slots on this bus */ struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */ @@ -243,6 +244,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 */ + struct list_head slots; /* list of slots under this bridge */ unsigned int devfn; /* encoded device & function index */ unsigned short vendor; @@ -767,8 +769,12 @@ void pcie_update_link_speed(struct pci_b void pcie_link_disable_set(struct pci_dev *dev, int bit); int pcie_link_disable_get(struct pci_dev *dev); int pcie_link_retrain(struct pci_dev *dev); -struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, - const char *name, +struct pci_slot *__pci_create_slot(struct pci_dev *b_dev, + struct pci_bus *parent, + int slot_nr, const char *name, + struct hotplug_slot *hotplug); +struct pci_slot *pci_create_slot(struct pci_bus *parent, + int slot_nr, const char *name, struct hotplug_slot *hotplug); void pci_destroy_slot(struct pci_slot *slot); void pci_renumber_slot(struct pci_slot *slot, int slot_nr); Index: linux-2.6/include/linux/pci_hotplug.h =================================================================== --- linux-2.6.orig/include/linux/pci_hotplug.h +++ linux-2.6/include/linux/pci_hotplug.h @@ -125,16 +125,20 @@ static inline const char *hotplug_slot_n return pci_slot_name(slot->pci_slot); } -extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_bus *pbus, - int nr, const char *name, +extern int __pci_hp_register(struct hotplug_slot *slot, struct pci_dev *b_dev, + struct pci_bus *pbus, int nr, const char *name, struct module *owner, const char *mod_name); 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); /* use a define to avoid include chaining to get THIS_MODULE & friends */ -#define pci_hp_register(slot, pbus, devnr, name) \ - __pci_hp_register(slot, pbus, devnr, name, THIS_MODULE, KBUILD_MODNAME) +#define pci_hp_register(slot, pbus, devnr, name) \ + __pci_hp_register(slot, NULL, pbus, devnr, name, THIS_MODULE, \ + KBUILD_MODNAME) +#define pci_hp_register_bridge(slot, b_dev, devnr, name) \ + __pci_hp_register(slot, b_dev, NULL, devnr, name, THIS_MODULE, \ + KBUILD_MODNAME) /* PCI Setting Record (Type 0) */ struct hpp_type0 {