diff options
author | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-23 13:30:20 +0200 |
---|---|---|
committer | Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de> | 2015-10-23 13:30:20 +0200 |
commit | e7549b926dd3ceec048f5689df90d4ec970c9419 (patch) | |
tree | c8645e0b4343c309aac1a3838a17cfcf0893d7b5 /drivers/pci/hotplug/acpiphp_glue.c | |
parent | 499ba610c2829adafbf393c2f3773d73ae4445f3 (diff) | |
download | kernel_samsung_smdk4412-e7549b926dd3ceec048f5689df90d4ec970c9419.zip kernel_samsung_smdk4412-e7549b926dd3ceec048f5689df90d4ec970c9419.tar.gz kernel_samsung_smdk4412-e7549b926dd3ceec048f5689df90d4ec970c9419.tar.bz2 |
more driver stuff from 3.2.72
Diffstat (limited to 'drivers/pci/hotplug/acpiphp_glue.c')
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 136 |
1 files changed, 114 insertions, 22 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 7bd3694..74d38ca 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -48,6 +48,7 @@ #include <linux/pci-acpi.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/acpi.h> #include "../pci.h" #include "acpiphp.h" @@ -110,7 +111,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val, } -static struct acpi_dock_ops acpiphp_dock_ops = { +static const struct acpi_dock_ops acpiphp_dock_ops = { .handler = handle_hotplug_event_func, }; @@ -140,6 +141,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) device = (adr >> 16) & 0xffff; function = adr & 0xffff; + pdev = pbus->self; + if (pdev && pci_is_pcie(pdev)) { + tmp = acpi_find_root_bridge_handle(pdev); + if (tmp) { + struct acpi_pci_root *root = acpi_pci_find_root(tmp); + + if (root && (root->osc_control_set & + OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) + return AE_OK; + } + } + newfunc = kzalloc(sizeof(struct acpiphp_func), GFP_KERNEL); if (!newfunc) return AE_NO_MEMORY; @@ -217,7 +230,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); if (pdev) { - pdev->current_state = PCI_D0; slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); pci_dev_put(pdev); } @@ -1154,15 +1166,35 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK ; } -/** - * handle_hotplug_event_bridge - handle ACPI event on bridges - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_bridge structure - * - * Handles ACPI event notification on {host,p2p} bridges. - */ -static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *context) +struct acpiphp_hp_work { + struct work_struct work; + acpi_handle handle; + u32 type; + void *context; +}; + +static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type, + void *context, + void (*func)(struct work_struct *work)) +{ + struct acpiphp_hp_work *hp_work; + int ret; + + hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL); + if (!hp_work) + return; + + hp_work->handle = handle; + hp_work->type = type; + hp_work->context = context; + + INIT_WORK(&hp_work->work, func); + ret = queue_work(kacpi_hotplug_wq, &hp_work->work); + if (!ret) + kfree(hp_work); +} + +static void _handle_hotplug_event_bridge(struct work_struct *work) { struct acpiphp_bridge *bridge; char objname[64]; @@ -1170,11 +1202,18 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont .pointer = objname }; struct acpi_device *device; int num_sub_bridges = 0; + struct acpiphp_hp_work *hp_work; + acpi_handle handle; + u32 type; + + hp_work = container_of(work, struct acpiphp_hp_work, work); + handle = hp_work->handle; + type = hp_work->type; if (acpi_bus_get_device(handle, &device)) { /* This bridge must have just been physically inserted */ handle_bridge_insertion(handle, type); - return; + goto out; } bridge = acpiphp_handle_to_bridge(handle); @@ -1185,7 +1224,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont if (!bridge && !num_sub_bridges) { err("cannot get bridge info\n"); - return; + goto out; } acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1246,22 +1285,49 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); break; } + +out: + kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ } /** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * handle_hotplug_event_bridge - handle ACPI event on bridges * @handle: Notify()'ed acpi_handle * @type: Notify code - * @context: pointer to acpiphp_func structure + * @context: pointer to acpiphp_bridge structure * - * Handles ACPI event notification on slots. + * Handles ACPI event notification on {host,p2p} bridges. */ -static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context) +static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, + void *context) +{ + /* + * Currently the code adds all hotplug events to the kacpid_wq + * queue when it should add hotplug events to the kacpi_hotplug_wq. + * The proper way to fix this is to reorganize the code so that + * drivers (dock, etc.) do not call acpi_os_execute(), etc. + * For now just re-add this work to the kacpi_hotplug_wq so we + * don't deadlock on hotplug actions. + */ + alloc_acpiphp_hp_work(handle, type, context, + _handle_hotplug_event_bridge); +} + +static void _handle_hotplug_event_func(struct work_struct *work) { struct acpiphp_func *func; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; + struct acpiphp_hp_work *hp_work; + acpi_handle handle; + u32 type; + void *context; + + hp_work = container_of(work, struct acpiphp_hp_work, work); + handle = hp_work->handle; + type = hp_work->type; + context = hp_work->context; acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1296,19 +1362,45 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); break; } + + kfree(hp_work); /* allocated in handle_hotplug_event_func */ } +/** + * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * @handle: Notify()'ed acpi_handle + * @type: Notify code + * @context: pointer to acpiphp_func structure + * + * Handles ACPI event notification on slots. + */ +static void handle_hotplug_event_func(acpi_handle handle, u32 type, + void *context) +{ + /* + * Currently the code adds all hotplug events to the kacpid_wq + * queue when it should add hotplug events to the kacpi_hotplug_wq. + * The proper way to fix this is to reorganize the code so that + * drivers (dock, etc.) do not call acpi_os_execute(), etc. + * For now just re-add this work to the kacpi_hotplug_wq so we + * don't deadlock on hotplug actions. + */ + alloc_acpiphp_hp_work(handle, type, context, + _handle_hotplug_event_func); +} static acpi_status find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { int *count = (int *)context; - if (acpi_is_root_bridge(handle)) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, NULL); - (*count)++; - } + if (!acpi_is_root_bridge(handle)) + return AE_OK; + + (*count)++; + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, NULL); + return AE_OK ; } |