diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 10:16:53 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-23 10:16:53 -0700 |
commit | a3415dc34f4a615a904852e7a9d0cc2877007e9e (patch) | |
tree | 0072b4b3f266c03220ffb2a9b329b2591f2a8e19 | |
parent | b4d0b08a4c3947c6ac004c9d83154ec5999c1861 (diff) | |
parent | 05a34f51ba451c65773ad6f1acf4cc089cc474d8 (diff) |
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (32 commits)
PCI hotplug: fix logic in Compaq hotplug controller bus speed setup
PCI: don't export linux/io.h from pci.h
PCI: PCI_QUIRKS depends on PCI
PCI hotplug: pciehp: poll data link layer link active
PCI hotplug: pciehp: fix possible memory leak in pcie_init
PCI: Workaround invalid P2P bridge bus numbers
PCI Hotplug: fakephp: add duplicate slot name debugging
PCI: Hotplug core: remove 'name'
PCI: shcphp: remove 'name' parameter
PCI: SGI Hotplug: stop managing bss_hotplug_slot->name
PCI: rpaphp: kmalloc/kfree slot->name directly
PCI: pciehp: remove 'name' parameter
PCI: ibmphp: stop managing hotplug_slot->name
PCI: fakephp: remove 'name' parameter
PCI, PCI Hotplug: introduce slot_name helpers
PCI: cpqphp: stop managing hotplug_slot->name
PCI: cpci_hotplug: stop managing hotplug_slot->name
PCI: acpiphp: remove 'name' parameter
PCI: prevent duplicate slot names
PCI Hotplug: serialize pci_hp_register and pci_hp_deregister
...
34 files changed, 637 insertions, 399 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index cecf1592609e..67fa3cff1749 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3257,11 +3257,6 @@ L: linux-pci@vger.kernel.org T: git kernel.org:/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git S: Supported -PCI HOTPLUG CORE -P: Kristen Carlson Accardi -M: kristen.c.accardi@intel.com -S: Supported - PCIE HOTPLUG DRIVER P: Kristen Carlson Accardi M: kristen.c.accardi@intel.com diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index d5b4ef898879..8d4a568be1cc 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -150,7 +150,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) } snprintf(name, sizeof(name), "%u", (u32)sun); - pci_slot = pci_create_slot(pci_bus, device, name); + pci_slot = pci_create_slot(pci_bus, device, name, NULL); if (IS_ERR(pci_slot)) { err("pci_create_slot returned %ld\n", PTR_ERR(pci_slot)); kfree(slot); diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h index 5a58b075dd8d..f9e244da30ae 100644 --- a/drivers/pci/hotplug/acpiphp.h +++ b/drivers/pci/hotplug/acpiphp.h @@ -50,9 +50,6 @@ #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) -/* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 20 /* {_SUN} */ - struct acpiphp_bridge; struct acpiphp_slot; @@ -63,9 +60,13 @@ struct slot { struct hotplug_slot *hotplug_slot; struct acpiphp_slot *acpi_slot; struct hotplug_slot_info info; - char name[SLOT_NAME_SIZE]; }; +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + /* * struct acpiphp_bridge - PCI bridge information * diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c index 0e496e866a84..95b536a23d25 100644 --- a/drivers/pci/hotplug/acpiphp_core.c +++ b/drivers/pci/hotplug/acpiphp_core.c @@ -44,6 +44,9 @@ #define MY_NAME "acpiphp" +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 21 /* {_SUN} */ + static int debug; int acpiphp_debug; @@ -84,7 +87,6 @@ static struct hotplug_slot_ops acpi_hotplug_slot_ops = { .get_adapter_status = get_adapter_status, }; - /** * acpiphp_register_attention - set attention LED callback * @info: must be completely filled with LED callbacks @@ -136,7 +138,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* enable the specified slot */ return acpiphp_enable_slot(slot->acpi_slot); @@ -154,7 +156,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); /* disable the specified slot */ retval = acpiphp_disable_slot(slot->acpi_slot); @@ -177,7 +179,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) { int retval = -ENODEV; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); if (attention_info && try_module_get(attention_info->owner)) { retval = attention_info->set_attn(hotplug_slot, status); @@ -200,7 +202,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_power_status(slot->acpi_slot); @@ -222,7 +224,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) { int retval = -EINVAL; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(hotplug_slot)); if (attention_info && try_module_get(attention_info->owner)) { retval = attention_info->get_attn(hotplug_slot, value); @@ -245,7 +247,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_latch_status(slot->acpi_slot); @@ -265,7 +267,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = acpiphp_get_adapter_status(slot->acpi_slot); @@ -299,7 +301,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot); kfree(slot); @@ -310,6 +312,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) { struct slot *slot; int retval = -ENOMEM; + char name[SLOT_NAME_SIZE]; slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) @@ -321,8 +324,6 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) slot->hotplug_slot->info = &slot->info; - slot->hotplug_slot->name = slot->name; - slot->hotplug_slot->private = slot; slot->hotplug_slot->release = &release_slot; slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; @@ -336,11 +337,12 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) slot->hotplug_slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN; acpiphp_slot->slot = slot; - snprintf(slot->name, sizeof(slot->name), "%u", slot->acpi_slot->sun); + snprintf(name, SLOT_NAME_SIZE, "%u", slot->acpi_slot->sun); retval = pci_hp_register(slot->hotplug_slot, acpiphp_slot->bridge->pci_bus, - acpiphp_slot->device); + acpiphp_slot->device, + name); if (retval == -EBUSY) goto error_hpslot; if (retval) { @@ -348,7 +350,7 @@ int acpiphp_register_hotplug_slot(struct acpiphp_slot *acpiphp_slot) goto error_hpslot; } - info("Slot [%s] registered\n", slot->hotplug_slot->name); + info("Slot [%s] registered\n", slot_name(slot)); return 0; error_hpslot: @@ -365,7 +367,7 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot) struct slot *slot = acpiphp_slot->slot; int retval = 0; - info ("Slot [%s] unregistered\n", slot->hotplug_slot->name); + info("Slot [%s] unregistered\n", slot_name(slot)); retval = pci_hp_deregister(slot->hotplug_slot); if (retval) diff --git a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h index d9769b30be9a..9fff878cf026 100644 --- a/drivers/pci/hotplug/cpci_hotplug.h +++ b/drivers/pci/hotplug/cpci_hotplug.h @@ -30,6 +30,7 @@ #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci_hotplug.h> /* PICMG 2.1 R2.0 HS CSR bits: */ #define HS_CSR_INS 0x0080 @@ -69,6 +70,11 @@ struct cpci_hp_controller { struct cpci_hp_controller_ops *ops; }; +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 935947991dc9..de94f4feef8c 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -108,7 +108,7 @@ enable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s", __func__, slot_name(slot)); if (controller->ops->set_power) retval = controller->ops->set_power(slot, 1); @@ -121,25 +121,23 @@ disable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; int retval = 0; - dbg("%s - physical_slot = %s", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s", __func__, slot_name(slot)); down_write(&list_rwsem); /* Unconfigure device */ - dbg("%s - unconfiguring slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - unconfiguring slot %s", __func__, slot_name(slot)); if ((retval = cpci_unconfigure_slot(slot))) { err("%s - could not unconfigure slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); goto disable_error; } - dbg("%s - finished unconfiguring slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - finished unconfiguring slot %s", __func__, slot_name(slot)); /* Clear EXT (by setting it) */ if (cpci_clear_ext(slot)) { err("%s - could not clear EXT for slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); retval = -ENODEV; goto disable_error; } @@ -214,7 +212,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); if (slot->dev) pci_dev_put(slot->dev); @@ -222,12 +219,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) } #define SLOT_NAME_SIZE 6 -static void -make_slot_name(struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, - SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); -} int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) @@ -235,7 +226,7 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; - char *name; + char name[SLOT_NAME_SIZE]; int status = -ENOMEM; int i; @@ -262,34 +253,31 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) goto error_hpslot; hotplug_slot->info = info; - name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!name) - goto error_info; - hotplug_slot->name = name; - slot->bus = bus; slot->number = i; slot->devfn = PCI_DEVFN(i, 0); + snprintf(name, SLOT_NAME_SIZE, "%02x:%02x", bus->number, i); + hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - make_slot_name(slot); hotplug_slot->ops = &cpci_hotplug_slot_ops; /* * Initialize the slot info structure with some known * good values. */ - dbg("initializing slot %s", slot->hotplug_slot->name); + dbg("initializing slot %s", name); info->power_status = cpci_get_power_status(slot); info->attention_status = cpci_get_attention_status(slot); - dbg("registering slot %s", slot->hotplug_slot->name); - status = pci_hp_register(slot->hotplug_slot, bus, i); + dbg("registering slot %s", name); + status = pci_hp_register(slot->hotplug_slot, bus, i, name); if (status) { err("pci_hp_register failed with error %d", status); - goto error_name; + goto error_info; } + dbg("slot registered with name: %s", slot_name(slot)); /* Add slot to our internal list */ down_write(&list_rwsem); @@ -298,8 +286,6 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) up_write(&list_rwsem); } return 0; -error_name: - kfree(name); error_info: kfree(info); error_hpslot: @@ -327,7 +313,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus) list_del(&slot->slot_list); slots--; - dbg("deregistering slot %s", slot->hotplug_slot->name); + dbg("deregistering slot %s", slot_name(slot)); status = pci_hp_deregister(slot->hotplug_slot); if (status) { err("pci_hp_deregister failed with error %d", @@ -379,11 +365,10 @@ init_slots(int clear_ins) return -1; } list_for_each_entry(slot, &slot_list, slot_list) { - dbg("%s - looking at slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - looking at slot %s", __func__, slot_name(slot)); if (clear_ins && cpci_check_and_clear_ins(slot)) dbg("%s - cleared INS for slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0)); if (dev) { if (update_adapter_status(slot->hotplug_slot, 1)) @@ -414,8 +399,7 @@ check_slots(void) } extracted = inserted = 0; list_for_each_entry(slot, &slot_list, slot_list) { - dbg("%s - looking at slot %s", - __func__, slot->hotplug_slot->name); + dbg("%s - looking at slot %s", __func__, slot_name(slot)); if (cpci_check_and_clear_ins(slot)) { /* * Some broken hardware (e.g. PLX 9054AB) asserts @@ -423,35 +407,34 @@ check_slots(void) */ if (slot->dev) { warn("slot %s already inserted", - slot->hotplug_slot->name); + slot_name(slot)); inserted++; continue; } /* Process insertion */ - dbg("%s - slot %s inserted", - __func__, slot->hotplug_slot->name); + dbg("%s - slot %s inserted", __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (1) = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); /* Configure device */ dbg("%s - configuring slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); if (cpci_configure_slot(slot)) { err("%s - could not configure slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); continue; } dbg("%s - finished configuring slot %s", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (2) = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); if (update_latch_status(slot->hotplug_slot, 1)) warn("failure to update latch file"); @@ -464,18 +447,18 @@ check_slots(void) /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR (3) = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); inserted++; } else if (cpci_check_ext(slot)) { /* Process extraction request */ dbg("%s - slot %s extracted", - __func__, slot->hotplug_slot->name); + __func__, slot_name(slot)); /* GSM, debug */ hs_csr = cpci_get_hs_csr(slot); dbg("%s - slot %s HS_CSR = %04x", - __func__, slot->hotplug_slot->name, hs_csr); + __func__, slot_name(slot), hs_csr); if (!slot->extracting) { if (update_latch_status(slot->hotplug_slot, 0)) { @@ -493,7 +476,7 @@ check_slots(void) * bother trying to tell the driver or not? */ err("card in slot %s was improperly removed", - slot->hotplug_slot->name); + slot_name(slot)); if (update_adapter_status(slot->hotplug_slot, 0)) warn("failure to update adapter file"); slot->extracting = 0; diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index df82b95e2874..829c327cfb5e 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -209,7 +209,7 @@ int cpci_led_on(struct slot* slot) hs_cap + 2, hs_csr)) { err("Could not set LOO for slot %s", - slot->hotplug_slot->name); + hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } @@ -238,7 +238,7 @@ int cpci_led_off(struct slot* slot) hs_cap + 2, hs_csr)) { err("Could not clear LOO for slot %s", - slot->hotplug_slot->name); + hotplug_slot_name(slot->hotplug_slot)); return -ENODEV; } } diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h index b1decfa88b7a..afaf8f69f73e 100644 --- a/drivers/pci/hotplug/cpqphp.h +++ b/drivers/pci/hotplug/cpqphp.h @@ -449,6 +449,11 @@ extern u8 cpqhp_disk_irq; /* inline functions */ +static inline char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + /* * return_resource * @@ -696,14 +701,6 @@ static inline int get_presence_status(struct controller *ctrl, struct slot *slot return presence_save; } -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot) -{ - snprintf(buffer, buffer_size, "%d", slot->number); -} - - static inline int wait_for_ctrl_irq(struct controller *ctrl) { DECLARE_WAITQUEUE(wait, current); diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 54defec51d08..724d42c4adbc 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -315,14 +315,15 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); kfree(slot); } +#define SLOT_NAME_SIZE 10 + static int ctrl_slot_setup(struct controller *ctrl, void __iomem *smbios_start, void __iomem *smbios_table) @@ -335,6 +336,7 @@ static int ctrl_slot_setup(struct controller *ctrl, u8 slot_number; u8 ctrl_slot; u32 tempdword; + char name[SLOT_NAME_SIZE]; void __iomem *slot_entry= NULL; int result = -ENOMEM; @@ -363,16 +365,12 @@ static int ctrl_slot_setup(struct controller *ctrl, if (!hotplug_slot->info) goto error_hpslot; hotplug_slot_info = hotplug_slot->info; - hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - - if (!hotplug_slot->name) - goto error_info; slot->ctrl = ctrl; slot->bus = ctrl->bus; slot->device = slot_device; slot->number = slot_number; - dbg("slot->number = %d\n", slot->number); + dbg("slot->number = %u\n", slot->number); slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); @@ -418,9 +416,9 @@ static int ctrl_slot_setup(struct controller *ctrl, /* register this slot with the hotplug pci core */ hotplug_slot->release = &release_slot; hotplug_slot->private = slot; - make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot); + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - + hotplug_slot_info->power_status = get_slot_enabled(ctrl, slot); hotplug_slot_info->attention_status = cpq_get_attention_status(ctrl, slot); @@ -436,10 +434,11 @@ static int ctrl_slot_setup(struct controller *ctrl, slot_number); result = pci_hp_register(hotplug_slot, ctrl->pci_dev->subordinate, - slot->device); + slot->device, + name); if (result) { err("pci_hp_register failed with error %d\n", result); - goto error_name; + goto error_info; } slot->next = ctrl->slot; @@ -451,8 +450,6 @@ static int ctrl_slot_setup(struct controller *ctrl, } return 0; -error_name: - kfree(hotplug_slot->name); error_info: kfree(hotplug_slot_info); error_hpslot: @@ -638,7 +635,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -665,7 +662,7 @@ static int process_SI(struct hotplug_slot *hotplug_slot) u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -697,7 +694,7 @@ static int process_SS(struct hotplug_slot *hotplug_slot) u8 device; u8 function; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) return -ENODEV; @@ -720,7 +717,7 @@ static int hardware_test(struct hotplug_slot *hotplug_slot, u32 value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return cpqhp_hardware_test(ctrl, value); } @@ -731,7 +728,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = get_slot_enabled(ctrl, slot); return 0; @@ -742,7 +739,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_attention_status(ctrl, slot); return 0; @@ -753,7 +750,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = cpq_get_latch_status(ctrl, slot); @@ -765,7 +762,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = get_presence_status(ctrl, slot); @@ -777,7 +774,7 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = ctrl->speed_capability; @@ -789,7 +786,7 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp struct slot *slot = hotplug_slot->private; struct controller *ctrl = slot->ctrl; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); *value = ctrl->speed; diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c index ef041ca91c27..a60a25290995 100644 --- a/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/drivers/pci/hotplug/cpqphp_ctrl.c @@ -1139,7 +1139,7 @@ static u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_ for(slot = ctrl->slot; slot; slot = slot->next) { if (slot->device == (hp_slot + ctrl->slot_device_offset)) continue; - if (!slot->hotplug_slot && !slot->hotplug_slot->info) + if (!slot->hotplug_slot || !slot->hotplug_slot->info) continue; if (slot->hotplug_slot->info->adapter_status == 0) continue; diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 146ca9cd1567..3a2637a00934 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -66,10 +66,10 @@ struct dummy_slot { struct pci_dev *dev; struct work_struct remove_work; unsigned long removed; - char name[8]; }; static int debug; +static int dup_slots; static LIST_HEAD(slot_list); static struct workqueue_struct *dummyphp_wq; @@ -96,10 +96,13 @@ static void dummy_release(struct hotplug_slot *slot) kfree(dslot); } +#define SLOT_NAME_SIZE 8 + static int add_slot(struct pci_dev *dev) { struct dummy_slot *dslot; struct hotplug_slot *slot; + char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; static int count = 1; @@ -119,19 +122,22 @@ static int add_slot(struct pci_dev *dev) 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); + if (dup_slots) + snprintf(name, SLOT_NAME_SIZE, "fake"); + else + snprintf(name, SLOT_NAME_SIZE, "fake%d", count++); + dbg("slot->name = %s\n", name); slot->ops = &dummy_hotplug_slot_ops; slot->release = &dummy_release; slot->private = dslot; - retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn)); + retval = pci_hp_register(slot, dev->bus, PCI_SLOT(dev->devfn), name); if (retval) { err("pci_hp_register failed with error %d\n", retval); goto error_dslot; } + dbg("slot->name = %s\n", hotplug_slot_name(slot)); dslot->slot = slot; dslot->dev = pci_dev_get(dev); list_add (&dslot->node, &slot_list); @@ -167,10 +173,11 @@ static void remove_slot(struct dummy_slot *dslot) { int retval; - dbg("removing slot %s\n", dslot->slot->name); + dbg("removing slot %s\n", hotplug_slot_name(dslot->slot)); retval = pci_hp_deregister(dslot->slot); if (retval) - err("Problem unregistering a slot %s\n", dslot->slot->name); + err("Problem unregistering a slot %s\n", + hotplug_slot_name(dslot->slot)); } /* called from the single-threaded workqueue handler to remove a slot */ @@ -308,7 +315,7 @@ static int disable_slot(struct hotplug_slot *slot) return -ENODEV; dslot = slot->private; - dbg("%s - physical_slot = %s\n", __func__, slot->name); + dbg("%s - physical_slot = %s\n", __func__, hotplug_slot_name(slot)); for (func = 7; func >= 0; func--) { dev = pci_get_slot(dslot->dev->bus, dslot->dev->devfn + func); @@ -373,4 +380,5 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - +module_param(dup_slots, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dup_slots, "Force duplicate slot names for debugging"); diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h index 612d96301509..a8d391a4957d 100644 --- a/drivers/pci/hotplug/ibmphp.h +++ b/drivers/pci/hotplug/ibmphp.h @@ -707,17 +707,16 @@ struct slot { u8 device; u8 number; u8 real_physical_slot_num; - char name[100]; u32 capabilities; u8 supported_speed; u8 supported_bus_mode; + u8 flag; /* this is for disable slot and polling */ + u8 ctlr_index; struct hotplug_slot *hotplug_slot; struct controller *ctrl; struct pci_func *func; u8 irq[4]; - u8 flag; /* this is for disable slot and polling */ int bit_mode; /* 0 = 32, 1 = 64 */ - u8 ctlr_index; struct bus_info *bus_on; struct list_head ibm_slot_list; u8 status; diff --git a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c index 8cfd1c4926c8..c1abac8ab5c3 100644 --- a/drivers/pci/hotplug/ibmphp_ebda.c +++ b/drivers/pci/hotplug/ibmphp_ebda.c @@ -587,11 +587,14 @@ static u8 calculate_first_slot (u8 slot_num) return first_slot + 1; } + +#define SLOT_NAME_SIZE 30 + static char *create_file_name (struct slot * slot_cur) { struct opt_rio *opt_vg_ptr = NULL; struct opt_rio_lo *opt_lo_ptr = NULL; - static char str[30]; + static char str[SLOT_NAME_SIZE]; int which = 0; /* rxe = 1, chassis = 0 */ u8 number = 1; /* either chassis or rxe # */ u8 first_slot = 1; @@ -703,7 +706,6 @@ static void release_slot(struct hotplug_slot *hotplug_slot) slot = hotplug_slot->private; kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); kfree(slot->hotplug_slot); slot->ctrl = NULL; slot->bus_on = NULL; @@ -734,6 +736,7 @@ static int __init ebda_rsrc_controller (void) struct bus_info *bus_info_ptr1, *bus_info_ptr2; int rc; struct slot *tmp_slot; + char name[SLOT_NAME_SIZE]; addr = hpc_list_ptr->phys_addr; for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { @@ -897,12 +900,6 @@ static int __init ebda_rsrc_controller (void) goto error_no_hp_info; } - hp_slot_ptr->name = kmalloc(30, GFP_KERNEL); - if (!hp_slot_ptr->name) { - rc = -ENOMEM; - goto error_no_hp_name; - } - tmp_slot = kzalloc(sizeof(*tmp_slot), GFP_KERNEL); if (!tmp_slot) { rc = -ENOMEM; @@ -964,9 +961,9 @@ static int __init ebda_rsrc_controller (void) } /* each hpc */ list_for_each_entry(tmp_slot, &ibmphp_slot_head, ibm_slot_list) { - snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); + snprintf(name, SLOT_NAME_SIZE, "%s", create_file_name(tmp_slot)); pci_hp_register(tmp_slot->hotplug_slot, - pci_find_bus(0, tmp_slot->bus), tmp_slot->device); + pci_find_bus(0, tmp_slot->bus), tmp_slot->device, name); } print_ebda_hpc (); @@ -976,8 +973,6 @@ static int __init ebda_rsrc_controller (void) error: kfree (hp_slot_ptr->private); error_no_slot: - kfree (hp_slot_ptr->name); -error_no_hp_name: kfree (hp_slot_ptr->info); error_no_hp_info: kfree (hp_slot_ptr); diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 2e6c4474644e..535fce0f07f9 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -37,6 +37,7 @@ #include <linux/init.h> #include <linux/mount.h> #include <linux/namei.h> +#include <linux/mutex.h> #include <linux/pci.h> #include <linux/pci_hotplug.h> #include <asm/uaccess.h> @@ -61,7 +62,7 @@ static int debug; ////////////////////////////////////////////////////////////////// static LIST_HEAD(pci_hotplug_slot_list); -static DEFINE_SPINLOCK(pci_hotplug_slot_list_lock); +static DEFINE_MUTEX(pci_hp_mutex); /* these strings match up with the values in pci_bus_speed */ static char *pci_bus_speed_strings[] = { @@ -530,16 +531,12 @@ static struct hotplug_slot *get_slot_from_name (const char *name) struct hotplug_slot *slot; struct list_head *tmp; - spin_lock(&pci_hotplug_slot_list_lock); list_for_each (tmp, &pci_hotplug_slot_list) { slot = list_entry (tmp, struct hotplug_slot, slot_list); - if (strcmp(slot->name, name) == 0) - goto out; + if (strcmp(hotplug_slot_name(slot), name) == 0) + return slot; } - slot = NULL; -out: - spin_unlock(&pci_hotplug_slot_list_lock); - return slot; + return NULL; } /** @@ -547,13 +544,15 @@ out: * @bus: bus this slot is on * @slot: pointer to the &struct hotplug_slot to register * @slot_nr: slot number + * @name: name registered with kobject core * * Registers a hotplug slot with the pci hotplug subsystem, which will allow * userspace interaction to the slot. * * Returns 0 if successful, anything else for an error. */ -int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr) +int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr, + const char *name) { int result; struct pci_slot *pci_slot; @@ -568,48 +567,29 @@ int pci_hp_register(struct hotplug_slot *slot, struct pci_bus *bus, int slot_nr) return -EINVAL; } - /* Check if we have already registered a slot with the same name. */ - if (get_slot_from_name(slot->name)) - return -EEXIST; + mutex_lock(&pci_hp_mutex); /* * 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); - - if (pci_slot->hotplug) { - dbg("%s: already claimed\n", __func__); - pci_destroy_slot(pci_slot); - return -EBUSY; + pci_slot = pci_create_slot(bus, slot_nr, name, slot); + if (IS_ERR(pci_slot)) { + result = PTR_ERR(pci_slot); + goto out; } slot->pci_slot = pci_slot; pci_slot->hotplug = slot; - /* - * Allow pcihp drivers to override the ACPI_PCI_SLOT name. - */ - if (strcmp(kobject_name(&pci_slot->kobj), slot->name)) { - result = kobject_rename(&pci_slot->kobj, slot->name); - if (result) { - pci_destroy_slot(pci_slot); - return result; - } - } - - spin_lock(&pci_hotplug_slot_list_lock); list_add(&slot->slot_list, &pci_hotplug_slot_list); - spin_unlock(&pci_hotplug_slot_list_lock); result = fs_add_slot(pci_slot); kobject_uevent(&pci_slot->kobj, KOBJ_ADD); - dbg("Added slot %s to the list\n", slot->name); - - + dbg("Added slot %s to the list\n", name); +out: + mutex_unlock(&pci_hp_mutex); return result; } @@ -630,21 +610,23 @@ int pci_hp_deregister(struct hotplug_slot *hotplug) if (!hotplug) return -ENODEV; - temp = get_slot_from_name(hotplug->name); - if (temp != hotplug) + mutex_lock(&pci_hp_mutex); + temp = get_slot_from_name(hotplug_slot_name(hotplug)); + if (temp != hotplug) { + mutex_unlock(&pci_hp_mutex); return -ENODEV; + } - spin_lock(&pci_hotplug_slot_list_lock); list_del(&hotplug->slot_list); - spin_unlock(&pci_hotplug_slot_list_lock); slot = hotplug->pci_slot; fs_remove_slot(slot); - dbg("Removed slot %s from the list\n", hotplug->name); + dbg("Removed slot %s from the list\n", hotplug_slot_name(hotplug)); hotplug->release(hotplug); slot->hotplug = NULL; pci_destroy_slot(slot); + mutex_unlock(&pci_hp_mutex); return 0; } diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index c367978bd7fe..a4817a841fae 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -74,15 +74,13 @@ extern struct workqueue_struct *pciehp_wq; struct slot { u8 bus; u8 device; - u32 number; u8 state; - struct timer_list task_event; u8 hp_slot; + u32 number; struct controller *ctrl; struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; - char name[SLOT_NAME_SIZE]; unsigned long last_emi_toggle; struct delayed_work work; /* work for button event */ struct mutex lock; @@ -112,6 +110,7 @@ struct controller { struct timer_list poll_timer; int cmd_busy; unsigned int no_cmd_complete:1; + unsigned int link_active_reporting:1; }; #define INT_BUTTON_IGNORE 0 @@ -175,6 +174,11 @@ int pciehp_enable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot); int pcie_enable_notification(struct controller *ctrl); +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device) { struct slot *slot; diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index c748a19db89d..62be1b59c74b 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -185,7 +185,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, hotplug_slot_name(hotplug_slot)); kfree(hotplug_slot->info); kfree(hotplug_slot); @@ -196,7 +196,7 @@ static int init_slots(struct controller *ctrl) struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; - int len, dup = 1; + char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; list_for_each_entry(slot, &ctrl->slot_list, slot_list) { @@ -210,41 +210,28 @@ static int init_slots(struct controller *ctrl) /* register this slot with the hotplug pci core */ hotplug_slot->info = info; - hotplug_slot->name = slot->name; hotplug_slot->private = slot; hotplug_slot->release = &release_slot; hotplug_slot->ops = &pciehp_hotplug_slot_ops; - get_power_status(hotplug_slot, &info->power_status); - get_attention_status(hotplug_slot, &info->attention_status); - get_latch_status(hotplug_slot, &info->latch_status); - get_adapter_status(hotplug_slot, &info->adapter_status); slot->hotplug_slot = hotplug_slot; + snprintf(name, SLOT_NAME_SIZE, "%u", slot->number); ctrl_dbg(ctrl, "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); -duplicate_name: retval = pci_hp_register(hotplug_slot, ctrl->pci_dev->subordinate, - slot->device); + slot->device, + name); if (retval) { - /* - * If slot N already exists, we'll try to create - * slot N-1, N-2 ... N-M, until we overflow. - */ - if (retval == -EEXIST) { - len = snprintf(slot->name, SLOT_NAME_SIZE, - "%d-%d", slot->number, dup++); - if (len < SLOT_NAME_SIZE) - goto duplicate_name; - else - ctrl_err(ctrl, "duplicate slot name " - "overflow\n"); - } ctrl_err(ctrl, "pci_hp_register failed with error %d\n", retval); goto error_info; } + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); /* create additional sysfs entries */ if (EMI(ctrl)) { retval = sysfs_create_file(&hotplug_slot->pci_slot->kobj, @@ -287,7 +274,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) struct slot *slot = hotplug_slot->private; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); hotplug_slot->info->attention_status = status; @@ -303,7 +290,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); return pciehp_sysfs_enable_slot(slot); } @@ -314,7 +301,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot) struct slot *slot = hotplug_slot->private; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); return pciehp_sysfs_disable_slot(slot); } @@ -325,7 +312,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) int retval; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); retval = slot->hpc_ops->get_power_status(slot, value); if (retval < 0) @@ -340,7 +327,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) int retval; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); retval = slot->hpc_ops->get_attention_status(slot, value); if (retval < 0) @@ -355,7 +342,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) int retval; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); retval = slot->hpc_ops->get_latch_status(slot, value); if (retval < 0) @@ -370,7 +357,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) int retval; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); retval = slot->hpc_ops->get_adapter_status(slot, value); if (retval < 0) @@ -386,7 +373,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, int retval; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) @@ -401,7 +388,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe int retval; ctrl_dbg(slot->ctrl, "%s - physical_slot = %s\n", - __func__, hotplug_slot->name); + __func__, slot_name(slot)); retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index acb7f9efd182..d6c5eb297753 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -66,7 +66,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot) /* * Button pressed - See if need to TAKE ACTION!!! */ - ctrl_info(ctrl, "Button pressed on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot)); event_type = INT_BUTTON_PRESS; queue_interrupt_event(p_slot, event_type); @@ -88,13 +88,13 @@ u8 pciehp_handle_switch_change(struct slot *p_slot) /* * Switch opened */ - ctrl_info(ctrl, "Latch open on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_OPEN; } else { /* * Switch closed */ - ctrl_info(ctrl, "Latch close on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_CLOSE; } @@ -120,13 +120,14 @@ u8 pciehp_handle_presence_change(struct slot *p_slot) /* * Card Present */ - ctrl_info(ctrl, "Card present on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Card present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - ctrl_info(ctrl, "Card not present on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Card not present on Slot(%s)\n", + slot_name(p_slot)); event_type = INT_PRESENCE_OFF; } @@ -148,13 +149,13 @@ u8 pciehp_handle_power_fault(struct slot *p_slot) * power fault Cleared */ ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n", - p_slot->name); + slot_name(p_slot)); event_type = INT_POWER_FAULT_CLEAR; } else { /* * power fault */ - ctrl_info(ctrl, "Power fault on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot)); event_type = INT_POWER_FAULT; ctrl_info(ctrl, "power fault bit %x set\n", 0); } @@ -225,9 +226,6 @@ static int board_added(struct slot *p_slot) if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for ~1 second */ - msleep(1000); - /* Check link training status */ retval = p_slot->hpc_ops->check_lnk_status(ctrl); if (retval) { @@ -412,12 +410,12 @@ static void handle_button_press_event(struct slot *p_slot) p_slot->state = BLINKINGOFF_STATE; ctrl_info(ctrl, "PCI slot #%s - powering off due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } else { p_slot->state = BLINKINGON_STATE; ctrl_info(ctrl, "PCI slot #%s - powering on due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } /* blink green LED and turn off amber */ if (PWR_LED(ctrl)) @@ -434,7 +432,7 @@ static void handle_button_press_event(struct slot *p_slot) * press the attention again before the 5 sec. limit * expires to cancel hot-add or hot-remove */ - ctrl_info(ctrl, "Button cancel on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot)); ctrl_dbg(ctrl, "%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) { @@ -447,7 +445,7 @@ static void handle_button_press_event(struct slot *p_slot) if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); ctrl_info(ctrl, "PCI slot #%s - action canceled " - "due to button press\n", p_slot->name); + "due to button press\n", slot_name(p_slot)); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: @@ -457,7 +455,7 @@ static void handle_button_press_event(struct slot *p_slot) * this means that the previous attention button action * to hot-add or hot-remove is undergoing */ - ctrl_info(ctrl, "Button ignore on Slot(%s)\n", p_slot->name); + ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); update_slot_info(p_slot); break; default: @@ -540,7 +538,7 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { ctrl_info(ctrl, "%s: no adapter on slot(%s)\n", - __func__, p_slot->name); + __func__, slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -548,7 +546,7 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { ctrl_info(ctrl, "%s: latch open on slot(%s)\n", - __func__, p_slot->name); + __func__, slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -558,7 +556,7 @@ int pciehp_enable_slot(struct slot *p_slot) rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { ctrl_info(ctrl, "%s: already enabled on slot(%s)\n", - __func__, p_slot->name); + __func__, slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -594,7 +592,7 @@ int pciehp_disable_slot(struct slot *p_slot) ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { ctrl_info(ctrl, "%s: no adapter on slot(%s)\n", - __func__, p_slot->name); + __func__, slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -604,7 +602,7 @@ int pciehp_disable_slot(struct slot *p_slot) ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { ctrl_info(ctrl, "%s: latch open on slot(%s)\n", - __func__, p_slot->name); + __func__, slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } @@ -614,7 +612,7 @@ int pciehp_disable_slot(struct slot *p_slot) ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { ctrl_info(ctrl, "%s: already disabled slot(%s)\n", - __func__, p_slot->name); + __func__, slot_name(p_slot)); mutex_unlock(&p_slot->ctrl->crit_sect); return -EINVAL; } @@ -645,14 +643,16 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot) break; case POWERON_STATE: ctrl_info(ctrl, "Slot %s is already in powering on state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGOFF_STATE: case POWEROFF_STATE: - ctrl_info(ctrl, "Already enabled on slot %s\n", p_slot->name); + ctrl_info(ctrl, "Already enabled on slot %s\n", + slot_name(p_slot)); break; default: - ctrl_err(ctrl, "Not a valid state on slot %s\n", p_slot->name); + ctrl_err(ctrl, "Not a valid state on slot %s\n", + slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); @@ -678,14 +678,16 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot) break; case POWEROFF_STATE: ctrl_info(ctrl, "Slot %s is already in powering off state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGON_STATE: case POWERON_STATE: - ctrl_info(ctrl, "Already disabled on slot %s\n", p_slot->name); + ctrl_info(ctrl, "Already disabled on slot %s\n", + slot_name(p_slot)); break; default: - ctrl_err(ctrl, "Not a valid state on slot %s\n", p_slot->name); + ctrl_err(ctrl, "Not a valid state on slot %s\n", + slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 8e9530c4c36d..58c72d2cc217 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -125,6 +125,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) /* Field definitions in Link Capabilities Register */ #define MAX_LNK_SPEED 0x000F #define MAX_LNK_WIDTH 0x03F0 +#define LINK_ACTIVE_REPORTING 0x00100000 /* Link Width Encoding */ #define LNK_X1 0x01 @@ -141,6 +142,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) #define LNK_TRN_ERR 0x0400 #define LNK_TRN 0x0800 #define SLOT_CLK_CONF 0x1000 +#define LINK_ACTIVE 0x2000 /* Field definitions in Slot Capabilities Register */ #define ATTN_BUTTN_PRSN 0x00000001 @@ -368,11 +370,52 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) return retval; } +static inline int check_link_active(struct controller *ctrl) +{ + u16 link_status; + + if (pciehp_readw(ctrl, LNKSTATUS, &link_status)) + return 0; + return !!(link_status & LINK_ACTIVE); +} + +static void pcie_wait_link_active(struct controller *ctrl) +{ + int timeout = 1000; + + if (check_link_active(ctrl)) + return; + while (timeout > 0) { + msleep(10); + timeout -= 10; + if (check_link_active(ctrl)) + return; + } + ctrl_dbg(ctrl, "Data Link Layer Link Active not set in 1000 msec\n"); +} + static int hpc_check_lnk_status(struct controller *ctrl) { u16 lnk_status; int retval = 0; + /* + * Data Link Layer Link Active Reporting must be capable for + * hot-plug capable downstream port. But old controller might + * not implement it. In this case, we wait for 1000 ms. + */ + if (ctrl->link_active_reporting){ + /* Wait for Data Link Layer Link Active bit to be set */ + pcie_wait_link_active(ctrl); + /* + * We must wait for 100 ms after the Data Link Layer + * Link Active bit reads 1b before initiating a + * configuration access to the hot added device. + */ + msleep(100); + } else + msleep(1000); + retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status); if (retval) { ctrl_err(ctrl, "%s: Cannot read LNKSTATUS register\n", @@ -1061,7 +1104,6 @@ static int pcie_init_slot(struct controller *ctrl) slot->device = ctrl->slot_device_offset + slot->hp_slot; slot->hpc_ops = ctrl->hpc_ops; slot->number = ctrl->first_slot; - snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); mutex_init(&slot->lock); INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); list_add(&slot->slot_list, &ctrl->slot_list); @@ -1132,7 +1174,7 @@ static inline void dbg_ctrl(struct controller *ctrl) struct controller *pcie_init(struct pcie_device *dev) { struct controller *ctrl; - u32 slot_cap; + u32 slot_cap, link_cap; struct pci_dev *pdev = dev->port; ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); @@ -1148,11 +1190,11 @@ struct controller *pcie_init(struct pcie_device *dev) if (!ctrl->cap_base) { ctrl_err(ctrl, "%s: Cannot find PCI Express capability\n", __func__); - goto abort; + goto abort_ctrl; } if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) { ctrl_err(ctrl, "%s: Cannot read SLOTCAP register\n", __func__); - goto abort; + goto abort_ctrl; } ctrl->slot_cap = slot_cap; @@ -1174,6 +1216,16 @@ struct controller *pcie_init(struct pcie_device *dev) !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl))) ctrl->no_cmd_complete = 1; + /* Check if Data Link Layer Link Active Reporting is implemented */ + if (pciehp_readl(ctrl, LNKCAP, &link_cap)) { + ctrl_err(ctrl, "%s: Cannot read LNKCAP register\n", __func__); + goto abort_ctrl; + } + if (link_cap & LINK_ACTIVE_REPORTING) { + ctrl_dbg(ctrl, "Link Active Reporting supported\n"); + ctrl->link_active_reporting = 1; + } + /* Clear all remaining event bits in Slot Status register */ if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) goto abort_ctrl; diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c index 50884507b8be..2ea9cf1a8d02 100644 --- a/drivers/pci/hotplug/rpaphp_slot.c +++ b/drivers/pci/hotplug/rpaphp_slot.c @@ -43,7 +43,7 @@ static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot) void dealloc_slot_struct(struct slot *slot) { kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); + kfree(slot->name); kfree(slot->hotplug_slot); kfree(slot); } @@ -63,11 +63,9 @@ struct slot *alloc_slot_struct(struct device_node *dn, GFP_KERNEL); if (!slot->hotplug_slot->info) goto error_hpslot; - slot->hotplug_slot->name = kmalloc(strlen(drc_name) + 1, GFP_KERNEL); - if (!slot->hotplug_slot->name) + slot->name = kstrdup(drc_name, GFP_KERNEL); + if (!slot->name) goto error_info; - slot->name = slot->hotplug_slot->name; - strcpy(slot->name, drc_name); slot->dn = dn; slot->index = drc_index; slot->power_domain = power_domain; @@ -137,7 +135,7 @@ int rpaphp_register_slot(struct slot *slot) slotno = PCI_SLOT(PCI_DN(slot->dn->child)->devfn); else slotno = -1; - retval = pci_hp_register(php_slot, slot->bus, slotno); + retval = pci_hp_register(php_slot, slot->bus, slotno, slot->name); 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 410fe0394a8e..d748698e31a2 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -161,7 +161,8 @@ static int sn_pci_bus_valid(struct pci_bus *pci_bus) } static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, - struct pci_bus *pci_bus, int device) + struct pci_bus *pci_bus, int device, + char *name) { struct pcibus_info *pcibus_info; struct slot *slot; @@ -173,15 +174,9 @@ 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; - } - slot->device_num = device; slot->pci_bus = pci_bus; - sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", + sprintf(name, "%04x:%02x:%02x", pci_domain_nr(pci_bus), ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum), device + 1); @@ -608,7 +603,6 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot) { kfree(bss_hotplug_slot->info); - kfree(bss_hotplug_slot->name); kfree(bss_hotplug_slot->private); kfree(bss_hotplug_slot); } @@ -618,6 +612,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) int device; struct pci_slot *pci_slot; struct hotplug_slot *bss_hotplug_slot; + char name[SN_SLOT_NAME_SIZE]; int rc = 0; /* @@ -645,15 +640,14 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) } if (sn_hp_slot_private_alloc(bss_hotplug_slot, - pci_bus, device)) { + pci_bus, device, name)) { rc = -ENOMEM; goto alloc_err; } - bss_hotplug_slot->ops = &sn_hotplug_slot_ops; bss_hotplug_slot->release = &sn_release_slot; - rc = pci_hp_register(bss_hotplug_slot, pci_bus, device); + rc = pci_hp_register(bss_hotplug_slot, pci_bus, device, name); if (rc) goto register_err; diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h index 8a026f750deb..4d9fed00e1d0 100644 --- a/drivers/pci/hotplug/shpchp.h +++ b/drivers/pci/hotplug/shpchp.h @@ -69,15 +69,13 @@ struct slot { u8 state; u8 presence_save; u8 pwr_save; - struct timer_list task_event; - u8 hp_slot; struct controller *ctrl; struct hpc_ops *hpc_ops; struct hotplug_slot *hotplug_slot; struct list_head slot_list; - char name[SLOT_NAME_SIZE]; struct delayed_work work; /* work for button event */ struct mutex lock; + u8 hp_slot; }; struct event_info { @@ -169,6 +167,11 @@ extern void cleanup_slots(struct controller *ctrl); extern void shpchp_queue_pushbutton_work(struct work_struct *work); extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev); +static inline const char *slot_name(struct slot *slot) +{ + return hotplug_slot_name(slot->hotplug_slot); +} + #ifdef CONFIG_ACPI #include <linux/pci-acpi.h> static inline int get_hp_params_from_firmware(struct pci_dev *dev, diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index cc38615395f1..7af9191df4d6 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -89,7 +89,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot) { struct slot *slot = hotplug_slot->private; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); kfree(slot->hotplug_slot->info); kfree(slot->hotplug_slot); @@ -101,8 +101,9 @@ static int init_slots(struct controller *ctrl) struct slot *slot; struct hotplug_slot *hotplug_slot; struct hotplug_slot_info *info; + char name[SLOT_NAME_SIZE]; int retval = -ENOMEM; - int i, len, dup = 1; + int i; for (i = 0; i < ctrl->num_slots; i++) { slot = kzalloc(sizeof(*slot), GFP_KERNEL); @@ -119,8 +120,6 @@ static int init_slots(struct controller *ctrl) goto error_hpslot; hotplug_slot->info = info; - hotplug_slot->name = slot->name; - slot->hp_slot = i; slot->ctrl = ctrl; slot->bus = ctrl->pci_dev->subordinate->number; @@ -133,37 +132,24 @@ static int init_slots(struct controller *ctrl) /* register this slot with the hotplug pci core */ hotplug_slot->private = slot; hotplug_slot->release = &release_slot; - snprintf(slot->name, SLOT_NAME_SIZE, "%d", slot->number); + snprintf(name, SLOT_NAME_SIZE, "%d", slot->number); hotplug_slot->ops = &shpchp_hotplug_slot_ops; - get_power_status(hotplug_slot, &info->power_status); - get_attention_status(hotplug_slot, &info->attention_status); - get_latch_status(hotplug_slot, &info->latch_status); - get_adapter_status(hotplug_slot, &info->adapter_status); - 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); -duplicate_name: retval = pci_hp_register(slot->hotplug_slot, - ctrl->pci_dev->subordinate, slot->device); + ctrl->pci_dev->subordinate, slot->device, name); if (retval) { - /* - * If slot N already exists, we'll try to create - * slot N-1, N-2 ... N-M, until we overflow. - */ - if (retval == -EEXIST) { - len = snprintf(slot->name, SLOT_NAME_SIZE, - "%d-%d", slot->number, dup++); - if (len < SLOT_NAME_SIZE) - goto duplicate_name; - else - err("duplicate slot name overflow\n"); - } err("pci_hp_register failed with error %d\n", retval); goto error_info; } + get_power_status(hotplug_slot, &info->power_status); + get_attention_status(hotplug_slot, &info->attention_status); + get_latch_status(hotplug_slot, &info->latch_status); + get_adapter_status(hotplug_slot, &info->adapter_status); + list_add(&slot->slot_list, &ctrl->slot_list); } @@ -201,7 +187,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) { struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); hotplug_slot->info->attention_status = status; slot->hpc_ops->set_attention_status(slot, status); @@ -213,7 +199,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot) { struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return shpchp_sysfs_enable_slot(slot); } @@ -222,7 +208,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot) { struct slot *slot = get_slot(hotplug_slot); - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); return shpchp_sysfs_disable_slot(slot); } @@ -232,7 +218,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_power_status(slot, value); if (retval < 0) @@ -246,7 +232,7 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_attention_status(slot, value); if (retval < 0) @@ -260,7 +246,7 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_latch_status(slot, value); if (retval < 0) @@ -274,7 +260,7 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_adapter_status(slot, value); if (retval < 0) @@ -289,7 +275,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_max_bus_speed(slot, value); if (retval < 0) @@ -303,7 +289,7 @@ static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp struct slot *slot = get_slot(hotplug_slot); int retval; - dbg("%s - physical_slot = %s\n", __func__, hotplug_slot->name); + dbg("%s - physical_slot = %s\n", __func__, slot_name(slot)); retval = slot->hpc_ops->get_cur_bus_speed(slot, value); if (retval < 0) diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index dfb53932dfbc..919b1ee44313 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -70,7 +70,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl) /* * Button pressed - See if need to TAKE ACTION!!! */ - info("Button pressed on Slot(%s)\n", p_slot->name); + info("Button pressed on Slot(%s)\n", slot_name(p_slot)); event_type = INT_BUTTON_PRESS; queue_interrupt_event(p_slot, event_type); @@ -98,7 +98,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl) /* * Switch opened */ - info("Latch open on Slot(%s)\n", p_slot->name); + info("Latch open on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_OPEN; if (p_slot->pwr_save && p_slot->presence_save) { event_type = INT_POWER_FAULT; @@ -108,7 +108,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl) /* * Switch closed */ - info("Latch close on Slot(%s)\n", p_slot->name); + info("Latch close on Slot(%s)\n", slot_name(p_slot)); event_type = INT_SWITCH_CLOSE; } @@ -135,13 +135,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl) /* * Card Present */ - info("Card present on Slot(%s)\n", p_slot->name); + info("Card present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_ON; } else { /* * Not Present */ - info("Card not present on Slot(%s)\n", p_slot->name); + info("Card not present on Slot(%s)\n", slot_name(p_slot)); event_type = INT_PRESENCE_OFF; } @@ -164,14 +164,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl) /* * Power fault Cleared */ - info("Power fault cleared on Slot(%s)\n", p_slot->name); + info("Power fault cleared on Slot(%s)\n", slot_name(p_slot)); p_slot->status = 0x00; event_type = INT_POWER_FAULT_CLEAR; } else { /* * Power fault */ - info("Power fault on Slot(%s)\n", p_slot->name); + info("Power fault on Slot(%s)\n", slot_name(p_slot)); event_type = INT_POWER_FAULT; /* set power fault status for this board */ p_slot->status = 0xFF; @@ -493,11 +493,11 @@ static void handle_button_press_event(struct slot *p_slot) if (getstatus) { p_slot->state = BLINKINGOFF_STATE; info("PCI slot #%s - powering off due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } else { p_slot->state = BLINKINGON_STATE; info("PCI slot #%s - powering on due to button " - "press.\n", p_slot->name); + "press.\n", slot_name(p_slot)); } /* blink green LED and turn off amber */ p_slot->hpc_ops->green_led_blink(p_slot); @@ -512,7 +512,7 @@ static void handle_button_press_event(struct slot *p_slot) * press the attention again before the 5 sec. limit * expires to cancel hot-add or hot-remove */ - info("Button cancel on Slot(%s)\n", p_slot->name); + info("Button cancel on Slot(%s)\n", slot_name(p_slot)); dbg("%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) @@ -521,7 +521,7 @@ static void handle_button_press_event(struct slot *p_slot) p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->set_attention_status(p_slot, 0); info("PCI slot #%s - action canceled due to button press\n", - p_slot->name); + slot_name(p_slot)); p_slot->state = STATIC_STATE; break; case POWEROFF_STATE: @@ -531,7 +531,7 @@ static void handle_button_press_event(struct slot *p_slot) * this means that the previous attention button action * to hot-add or hot-remove is undergoing */ - info("Button ignore on Slot(%s)\n", p_slot->name); + info("Button ignore on Slot(%s)\n", slot_name(p_slot)); update_slot_info(p_slot); break; default: @@ -574,17 +574,17 @@ static int shpchp_enable_slot (struct slot *p_slot) mutex_lock(&p_slot->ctrl->crit_sect); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("No adapter on slot(%s)\n", p_slot->name); + info("No adapter on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("Latch open on slot(%s)\n", p_slot->name); + info("Latch open on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { - info("Already enabled on slot(%s)\n", p_slot->name); + info("Already enabled on slot(%s)\n", slot_name(p_slot)); goto out; } @@ -633,17 +633,17 @@ static int shpchp_disable_slot (struct slot *p_slot) rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { - info("No adapter on slot(%s)\n", p_slot->name); + info("No adapter on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { - info("Latch open on slot(%s)\n", p_slot->name); + info("Latch open on slot(%s)\n", slot_name(p_slot)); goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || !getstatus) { - info("Already disabled slot(%s)\n", p_slot->name); + info("Already disabled slot(%s)\n", slot_name(p_slot)); goto out; } @@ -671,14 +671,14 @@ int shpchp_sysfs_enable_slot(struct slot *p_slot) break; case POWERON_STATE: info("Slot %s is already in powering on state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGOFF_STATE: case POWEROFF_STATE: - info("Already enabled on slot %s\n", p_slot->name); + info("Already enabled on slot %s\n", slot_name(p_slot)); break; default: - err("Not a valid state on slot %s\n", p_slot->name); + err("Not a valid state on slot %s\n", slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); @@ -703,14 +703,14 @@ int shpchp_sysfs_disable_slot(struct slot *p_slot) break; case POWEROFF_STATE: info("Slot %s is already in powering off state\n", - p_slot->name); + slot_name(p_slot)); break; case BLINKINGON_STATE: case POWERON_STATE: - info("Already disabled on slot %s\n", p_slot->name); + info("Already disabled on slot %s\n", slot_name(p_slot)); break; default: - err("Not a valid state on slot %s\n", p_slot->name); + err("Not a valid state on slot %s\n", slot_name(p_slot)); break; } mutex_unlock(&p_slot->lock); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index d2812013fd22..74801f7df9c9 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -759,3 +759,24 @@ void pci_msi_init_pci_dev(struct pci_dev *dev) { INIT_LIST_HEAD(&dev->msi_list); } + +#ifdef CONFIG_ACPI +#include <linux/acpi.h> +#include <linux/pci-acpi.h> +static void __devinit msi_acpi_init(void) +{ + if (acpi_pci_disabled) + return; + pci_osc_support_set(OSC_MSI_SUPPORT); + pcie_osc_support_set(OSC_MSI_SUPPORT); +} +#else +static inline void msi_acpi_init(void) { } +#endif /* CONFIG_ACPI */ + +void __devinit msi_init(void) +{ + if (!pci_msi_enable) + return; + msi_acpi_init(); +} diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 89a2f0fa10f9..dfe7c8e1b185 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -24,17 +24,17 @@ struct acpi_osc_data { acpi_handle handle; u32 support_set; u32 control_set; - int is_queried; - u32 query_result; struct list_head sibiling; }; static LIST_HEAD(acpi_osc_data_list); struct acpi_osc_args { u32 capbuf[3]; - u32 query_result; + u32 ctrl_result; }; +static DEFINE_MUTEX(pci_acpi_lock); + static struct acpi_osc_data *acpi_get_osc_data(acpi_handle handle) { struct acpi_osc_data *data; @@ -108,9 +108,8 @@ static acpi_status acpi_run_osc(acpi_handle handle, goto out_kfree; } out_success: - if (flags & OSC_QUERY_ENABLE) - osc_args->query_result = - *((u32 *)(out_obj->buffer.pointer + 8)); + osc_args->ctrl_result = + *((u32 *)(out_obj->buffer.pointer + 8)); status = AE_OK; out_kfree: @@ -118,41 +117,53 @@ out_kfree: return status; } -static acpi_status acpi_query_osc(acpi_handle handle, - u32 level, void *context, void **retval) +static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data, + u32 *result) { acpi_status status; - struct acpi_osc_data *osc_data; - u32 flags = (unsigned long)context, support_set; - acpi_handle tmp; + u32 support_set; struct acpi_osc_args osc_args; - status = acpi_get_handle(handle, "_OSC", &tmp); - if (ACPI_FAILURE(status)) - return status; - - osc_data = acpi_get_osc_data(handle); - if (!osc_data) { - printk(KERN_ERR "acpi osc data array is full\n"); - return AE_ERROR; - } - /* do _OSC query for all possible controls */ support_set = osc_data->support_set | (flags & OSC_SUPPORT_MASKS); osc_args.capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; osc_args.capbuf[OSC_SUPPORT_TYPE] = support_set; osc_args.capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; - status = acpi_run_osc(handle, &osc_args); + status = acpi_run_osc(osc_data->handle, &osc_args); if (ACPI_SUCCESS(status)) { osc_data->support_set = support_set; - osc_data->query_result = osc_args.query_result; - osc_data->is_queried = 1; + *result = osc_args.ctrl_result; } return status; } +static acpi_status acpi_query_osc(acpi_handle handle, + u32 level, void *context, void **retval) +{ + acpi_status status; + struct acpi_osc_data *osc_data; + u32 flags = (unsigned long)context, dummy; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_OSC", &tmp); + if (ACPI_FAILURE(status)) + return AE_OK; + + mutex_lock(&pci_acpi_lock); + osc_data = acpi_get_osc_data(handle); + if (!osc_data) { + printk(KERN_ERR "acpi osc data array is full\n"); + goto out; + } + + __acpi_query_osc(flags, osc_data, &dummy); +out: + mutex_unlock(&pci_acpi_lock); + return AE_OK; +} + /** * __pci_osc_support_set - register OS support to Firmware * @flags: OS support bits @@ -181,7 +192,7 @@ acpi_status __pci_osc_support_set(u32 flags, const char *hid) acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) { acpi_status status; - u32 ctrlset, control_set; + u32 ctrlset, control_set, result; acpi_handle tmp; struct acpi_osc_data *osc_data; struct acpi_osc_args osc_args; @@ -190,19 +201,28 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) if (ACPI_FAILURE(status)) return status; + mutex_lock(&pci_acpi_lock); osc_data = acpi_get_osc_data(handle); if (!osc_data) { printk(KERN_ERR "acpi osc data array is full\n"); - return AE_ERROR; + status = AE_ERROR; + goto out; } ctrlset = (flags & OSC_CONTROL_MASKS); - if (!ctrlset) - return AE_TYPE; + if (!ctrlset) { + status = AE_TYPE; + goto out; + } - if (osc_data->is_queried && - ((osc_data->query_result & ctrlset) != ctrlset)) - return AE_SUPPORT; + status = __acpi_query_osc(osc_data->support_set, osc_data, &result); + if (ACPI_FAILURE(status)) + goto out; + + if ((result & ctrlset) != ctrlset) { + status = AE_SUPPORT; + goto out; + } control_set = osc_data->control_set | ctrlset; osc_args.capbuf[OSC_QUERY_TYPE] = 0; @@ -211,7 +231,8 @@ acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) status = acpi_run_osc(handle, &osc_args); if (ACPI_SUCCESS(status)) osc_data->control_set = control_set; - +out: + mutex_unlock(&pci_acpi_lock); return status; } EXPORT_SYMBOL(pci_osc_control_set); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4db261e13e69..533aeb5fcbe4 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -18,6 +18,7 @@ #include <linux/log2.h> #include <linux/pci-aspm.h> #include <linux/pm_wakeup.h> +#include <linux/interrupt.h> #include <asm/dma.h> /* isa_dma_bridge_buggy */ #include "pci.h" @@ -1746,6 +1747,103 @@ EXPORT_SYMBOL(pci_set_dma_seg_boundary); #endif /** + * pci_execute_reset_function() - Reset a PCI device function + * @dev: Device function to reset + * + * Some devices allow an individual function to be reset without affecting + * other functions in the same device. The PCI device must be responsive + * to PCI config space in order to use this function. + * + * The device function is presumed to be unused when this function is called. + * Resetting the device will make the contents of PCI configuration space + * random, so any caller of this must be prepared to reinitialise the + * device including MSI, bus mastering, BARs, decoding IO and memory spaces, + * etc. + * + * Returns 0 if the device function was successfully reset or -ENOTTY if the + * device doesn't support resetting a single function. + */ +int pci_execute_reset_function(struct pci_dev *dev) +{ + u16 status; + u32 cap; + int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); + + if (!exppos) + return -ENOTTY; + pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return -ENOTTY; + + pci_block_user_cfg_access(dev); + + /* Wait for Transaction Pending bit clean */ + msleep(100); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) { + dev_info(&dev->dev, "Busy after 100ms while trying to reset; " + "sleeping for 1 second\n"); + ssleep(1); + pci_read_config_word(dev, exppos + PCI_EXP_DEVSTA, &status); + if (status & PCI_EXP_DEVSTA_TRPND) + dev_info(&dev->dev, "Still busy after 1s; " + "proceeding with reset anyway\n"); + } + + pci_write_config_word(dev, exppos + PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_BCR_FLR); + mdelay(100); + + pci_unblock_user_cfg_access(dev); + return 0; +} +EXPORT_SYMBOL_GPL(pci_execute_reset_function); + +/** + * pci_reset_function() - quiesce and reset a PCI device function + * @dev: Device function to reset + * + * Some devices allow an individual function to be reset without affecting + * other functions in the same device. The PCI device must be responsive + * to PCI config space in order to use this function. + * + * This function does not just reset the PCI portion of a device, but + * clears all the state associated with the device. This function differs + * from pci_execute_reset_function in that it saves and restores device state + * over the reset. + * + * Returns 0 if the device function was successfully reset or -ENOTTY if the + * device doesn't support resetting a single function. + */ +int pci_reset_function(struct pci_dev *dev) +{ + u32 cap; + int exppos = pci_find_capability(dev, PCI_CAP_ID_EXP); + int r; + + if (!exppos) + return -ENOTTY; + pci_read_config_dword(dev, exppos + PCI_EXP_DEVCAP, &cap); + if (!(cap & PCI_EXP_DEVCAP_FLR)) + return -ENOTTY; + + if (!dev->msi_enabled && !dev->msix_enabled) + disable_irq(dev->irq); + pci_save_state(dev); + + pci_write_config_word(dev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE); + + r = pci_execute_reset_function(dev); + + pci_restore_state(dev); + if (!dev->msi_enabled && !dev->msix_enabled) + enable_irq(dev->irq); + + return r; +} +EXPORT_SYMBOL_GPL(pci_reset_function); + +/** * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count * @dev: PCI device to query * @@ -1933,6 +2031,9 @@ static int __devinit pci_init(void) while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_fixup_device(pci_fixup_final, dev); } + + msi_init(); + return 0; } diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index b205ab866a1d..9de87e9f98f5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -98,9 +98,11 @@ extern unsigned int pci_pm_d3_delay; #ifdef CONFIG_PCI_MSI void pci_no_msi(void); extern void pci_msi_init_pci_dev(struct pci_dev *dev); +extern void __devinit msi_init(void); #else static inline void pci_no_msi(void) { } static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { } +static inline void msi_init(void) { } #endif #ifdef CONFIG_PCIEAER diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index aaaf0a1fed22..6f1e51d77bce 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -480,19 +480,27 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); u32 buses, i, j = 0; u16 bctl; + int broken = 0; pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses); dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n", buses & 0xffffff, pass); + /* Check if setup is sensible at all */ + if (!pass && + ((buses & 0xff) != bus->number || ((buses >> 8) & 0xff) <= bus->number)) { + dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n"); + broken = 1; + } + /* Disable MasterAbortMode during probing to avoid reporting of bus errors (in some architectures) */ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bctl); pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); - if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) { + if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus && !broken) { unsigned int cmax, busnr; /* * Bus already configured by firmware, process it in the first @@ -530,7 +538,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, * do in the second pass. */ if (!pass) { - if (pcibios_assign_all_busses()) + if (pcibios_assign_all_busses() || broken) /* Temporarily disable forwarding of the configuration cycles on all bridges in this bus segment to avoid possible diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 4edfc4731bd4..5af8bd538149 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -166,6 +166,7 @@ struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, { struct pci_dev *pdev; + pci_dev_get(from); pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); pci_dev_put(pdev); return pdev; @@ -270,12 +271,8 @@ static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id, struct pci_dev *pdev = NULL; WARN_ON(in_interrupt()); - if (from) { - /* FIXME - * take the cast off, when bus_find_device is made const. - */ - dev_start = (struct device *)&from->dev; - } + if (from) + dev_start = &from->dev; dev = bus_find_device(&pci_bus_type, dev_start, (void *)id, match_pci_dev_by_id); if (dev) diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 0c6db03698ea..4dd1c3e157ae 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -78,18 +78,100 @@ static struct kobj_type pci_slot_ktype = { .default_attrs = pci_slot_default_attrs, }; +static char *make_slot_name(const char *name) +{ + char *new_name; + int len, max, dup; + + new_name = kstrdup(name, GFP_KERNEL); + if (!new_name) + return NULL; + + /* + * Make sure we hit the realloc case the first time through the + * loop. 'len' will be strlen(name) + 3 at that point which is + * enough space for "name-X" and the trailing NUL. + */ + len = strlen(name) + 2; + max = 1; + dup = 1; + + for (;;) { + struct kobject *dup_slot; + dup_slot = kset_find_obj(pci_slots_kset, new_name); + if (!dup_slot) + break; + kobject_put(dup_slot); + if (dup == max) { + len++; + max *= 10; + kfree(new_name); + new_name = kmalloc(len, GFP_KERNEL); + if (!new_name) + break; + } + sprintf(new_name, "%s-%d", name, dup++); + } + + return new_name; +} + +static int rename_slot(struct pci_slot *slot, const char *name) +{ + int result = 0; + char *slot_name; + + if (strcmp(pci_slot_name(slot), name) == 0) + return result; + + slot_name = make_slot_name(name); + if (!slot_name) + return -ENOMEM; + + result = kobject_rename(&slot->kobj, slot_name); + kfree(slot_name); + + return result; +} + +static struct pci_slot *get_slot(struct pci_bus *parent, int slot_nr) +{ + struct pci_slot *slot; + /* + * We already hold pci_bus_sem so don't worry + */ + list_for_each_entry(slot, &parent->slots, list) + if (slot->number == slot_nr) { + kobject_get(&slot->kobj); + return slot; + } + + return NULL; +} + /** * pci_create_slot - create or increment refcount for physical PCI slot * @parent: struct pci_bus of parent bridge * @slot_nr: PCI_SLOT(pci_dev->devfn) or -1 for placeholder * @name: user visible string presented in /sys/bus/pci/slots/<name> + * @hotplug: set if caller is hotplug driver, NULL otherwise * * PCI slots have first class attributes such as address, speed, width, * and a &struct pci_slot is used to manage them. This interface will * either return a new &struct pci_slot to the caller, or if the pci_slot * already exists, its refcount will be incremented. * - * Slots are uniquely identified by a @pci_bus, @slot_nr, @name tuple. + * Slots are uniquely identified by a @pci_bus, @slot_nr tuple. + * + * There are known platforms with broken firmware that assign the same + * name to multiple slots. Workaround these broken platforms by renaming + * the slots on behalf of the caller. If firmware assigns name N to + * multiple slots: + * + * The first slot is assigned N + * The second slot is assigned N-1 + * The third slot is assigned N-2 + * etc. * * Placeholder slots: * In most cases, @pci_bus, @slot_nr will be sufficient to uniquely identify @@ -98,61 +180,67 @@ static struct kobj_type pci_slot_ktype = { * the slot. In this scenario, the caller may pass -1 for @slot_nr. * * The following semantics are imposed when the caller passes @slot_nr == - * -1. First, the check for existing %struct pci_slot is skipped, as the - * caller may know about several unpopulated slots on a given %struct - * pci_bus, and each slot would have a @slot_nr of -1. Uniqueness for - * these slots is then determined by the @name parameter. We expect - * kobject_init_and_add() to warn us if the caller attempts to create - * multiple slots with the same name. The other change in semantics is + * -1. First, we no longer check for an existing %struct pci_slot, as there + * may be many slots with @slot_nr of -1. The other change in semantics is * user-visible, which is the 'address' parameter presented in sysfs will * consist solely of a dddd:bb tuple, where dddd is the PCI domain of the * %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) + const char *name, + struct hotplug_slot *hotplug) { struct pci_dev *dev; struct pci_slot *slot; - int err; + int err = 0; + char *slot_name = NULL; down_write(&pci_bus_sem); if (slot_nr == -1) goto placeholder; - /* If we've already created this slot, bump refcount and return. */ - list_for_each_entry(slot, &parent->slots, list) { - if (slot->number == slot_nr) { - kobject_get(&slot->kobj); - pr_debug("%s: inc refcount to %d on %04x:%02x:%02x\n", - __func__, - atomic_read(&slot->kobj.kref.refcount), - pci_domain_nr(parent), parent->number, - slot_nr); - goto out; + /* + * Hotplug drivers are allowed to rename an existing slot, + * but only if not already claimed. + */ + slot = get_slot(parent, slot_nr); + if (slot) { + if (hotplug) { + if ((err = slot->hotplug ? -EBUSY : 0) + || (err = rename_slot(slot, name))) { + kobject_put(&slot->kobj); + slot = NULL; + goto err; + } } + goto out; } placeholder: slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) { - slot = ERR_PTR(-ENOMEM); - goto out; + err = -ENOMEM; + goto err; } slot->bus = parent; slot->number = slot_nr; slot->kobj.kset = pci_slots_kset; - err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, - "%s", name); - if (err) { - printk(KERN_ERR "Unable to register kobject %s\n", name); + + slot_name = make_slot_name(name); + if (!slot_name) { + err = -ENOMEM; goto err; } + err = kobject_init_and_add(&slot->kobj, &pci_slot_ktype, NULL, + "%s", slot_name); + if (err) + goto err; + INIT_LIST_HEAD(&slot->list); list_add(&slot->list, &parent->slots); @@ -164,10 +252,10 @@ placeholder: pr_debug("%s: created pci_slot on %04x:%02x:%02x\n", __func__, pci_domain_nr(parent), parent->number, slot_nr); - out: +out: up_write(&pci_bus_sem); return slot; - err: +err: kfree(slot); slot = ERR_PTR(err); goto out; @@ -175,7 +263,7 @@ placeholder: EXPORT_SYMBOL_GPL(pci_create_slot); /** - * pci_update_slot_number - update %struct pci_slot -> number + * pci_renumber_slot - update %struct pci_slot -> number * @slot - %struct pci_slot to update * @slot_nr - new number for slot * @@ -183,27 +271,22 @@ EXPORT_SYMBOL_GPL(pci_create_slot); * created a placeholder slot in pci_create_slot() by passing a -1 as * slot_nr, to update their %struct pci_slot with the correct @slot_nr. */ - -void pci_update_slot_number(struct pci_slot *slot, int slot_nr) +void pci_renumber_slot(struct pci_slot *slot, int slot_nr) { - int name_count = 0; struct pci_slot *tmp; down_write(&pci_bus_sem); list_for_each_entry(tmp, &slot->bus->slots, list) { WARN_ON(tmp->number == slot_nr); - if (!strcmp(kobject_name(&tmp->kobj), kobject_name(&slot->kobj))) - name_count++; + goto out; } - if (name_count > 1) - printk(KERN_WARNING "pci_update_slot_number found %d slots with the same name: %s\n", name_count, kobject_name(&slot->kobj)); - slot->number = slot_nr; +out: up_write(&pci_bus_sem); } -EXPORT_SYMBOL_GPL(pci_update_slot_number); +EXPORT_SYMBOL_GPL(pci_renumber_slot); /** * pci_destroy_slot - decrement refcount for physical PCI slot @@ -213,7 +296,6 @@ EXPORT_SYMBOL_GPL(pci_update_slot_number); * just call kobject_put on its kobj and let our release methods do the * rest. */ - void pci_destroy_slot(struct pci_slot *slot) { pr_debug("%s: dec refcount to %d on %04x:%02x:%02x\n", __func__, diff --git a/include/linux/pci.h b/include/linux/pci.h index 085187be29c7..752def8a2ef4 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -51,6 +51,7 @@ #include <linux/kobject.h> #include <asm/atomic.h> #include <linux/device.h> +#include <linux/io.h> /* Include the ID list */ #include <linux/pci_ids.h> @@ -64,6 +65,11 @@ struct pci_slot { struct kobject kobj; }; +static inline const char *pci_slot_name(const struct pci_slot *slot) +{ + return kobject_name(&slot->kobj); +} + /* File state for mmap()s on /proc/bus/pci/X/Y */ enum pci_mmap_state { pci_mmap_io, @@ -509,9 +515,10 @@ struct pci_bus *pci_create_bus(struct device *parent, int bus, 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); + const char *name, + struct hotplug_slot *hotplug); void pci_destroy_slot(struct pci_slot *slot); -void pci_update_slot_number(struct pci_slot *slot, int slot_nr); +void pci_renumber_slot(struct pci_slot *slot, int slot_nr); 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); @@ -626,6 +633,8 @@ int pcix_get_mmrbc(struct pci_dev *dev); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); int pcie_get_readrq(struct pci_dev *dev); int pcie_set_readrq(struct pci_dev *dev, int rq); +int pci_reset_function(struct pci_dev *dev); +int pci_execute_reset_function(struct pci_dev *dev); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int pci_select_bars(struct pci_dev *dev, unsigned long flags); diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index a08cd06b541a..a00bd1a0f156 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -142,8 +142,6 @@ struct hotplug_slot_info { /** * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot * @info: pointer to the &struct hotplug_slot_info for the initial values for * this slot. @@ -153,7 +151,6 @@ struct hotplug_slot_info { * needs. */ struct hotplug_slot { - char *name; struct hotplug_slot_ops *ops; struct hotplug_slot_info *info; void (*release) (struct hotplug_slot *slot); @@ -165,7 +162,13 @@ struct hotplug_slot { }; #define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj) -extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr); +static inline const char *hotplug_slot_name(const struct hotplug_slot *slot) +{ + return pci_slot_name(slot->pci_slot); +} + +extern int pci_hp_register(struct hotplug_slot *, struct pci_bus *, int nr, + const char *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); diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index eb6686b88f9a..e5effd47ed74 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -377,6 +377,7 @@ #define PCI_EXP_DEVCAP_RBER 0x8000 /* Role-Based Error Reporting */ #define PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ #define PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ #define PCI_EXP_DEVCTL 8 /* Device Control */ #define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ #define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ @@ -389,6 +390,7 @@ #define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ #define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ #define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ #define PCI_EXP_DEVSTA 10 /* Device Status */ #define PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ #define PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ diff --git a/init/Kconfig b/init/Kconfig index 113c74c07da4..44e9208f9c78 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -739,7 +739,8 @@ config VM_EVENT_COUNTERS config PCI_QUIRKS default y - bool "Enable PCI quirk workarounds" if EMBEDDED && PCI + bool "Enable PCI quirk workarounds" if EMBEDDED + depends on PCI help This enables workarounds for various PCI chipset bugs/quirks. Disable this only if your target machine is |