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 ...
This commit is contained in:
commit
a3415dc34f
34 changed files with 641 additions and 403 deletions
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
|
|||
* @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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
|
||||
"slot_device_offset=%x\n", slot->bus, slot->device,
|
||||
slot->hp_slot, slot->number, ctrl->slot_device_offset);
|
||||
retval = pci_hp_register(slot->hotplug_slot,
|
||||
ctrl->pci_dev->subordinate, slot->device, name);
|
||||
if (retval) {
|
||||
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);
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,39 +117,51 @@ static acpi_status acpi_run_osc(acpi_handle handle,
|
|||
return status;
|
||||
}
|
||||
|
||||
static acpi_status __acpi_query_osc(u32 flags, struct acpi_osc_data *osc_data,
|
||||
u32 *result)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 support_set;
|
||||
struct acpi_osc_args osc_args;
|
||||
|
||||
/* 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(osc_data->handle, &osc_args);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
osc_data->support_set = support_set;
|
||||
*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, support_set;
|
||||
u32 flags = (unsigned long)context, dummy;
|
||||
acpi_handle tmp;
|
||||
struct acpi_osc_args osc_args;
|
||||
|
||||
status = acpi_get_handle(handle, "_OSC", &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 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");
|
||||
return AE_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
osc_data->support_set = support_set;
|
||||
osc_data->query_result = osc_args.query_result;
|
||||
osc_data->is_queried = 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
__acpi_query_osc(flags, osc_data, &dummy);
|
||||
out:
|
||||
mutex_unlock(&pci_acpi_lock);
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -1745,6 +1746,103 @@ int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
|||
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 @@ struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr,
|
|||
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__,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue