Commit 6621c5a6 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'acpi-hotplug'

* acpi-hotplug:
  ACPI / hotplug: Rework deferred execution of acpi_device_hotplug()
  ACPI / dock: Update copyright notice
  ACPI / dock: Drop remove_dock_dependent_devices()
  ACPI / dock: Drop struct acpi_dock_ops and all code related to it
  ACPI / ATA: Add hotplug contexts to ACPI companions of SATA devices
  ACPI / dock: Add .uevent() callback to struct acpi_hotplug_context
  ACPI / dock: Use callback pointers from devices' ACPI hotplug contexts
  ACPI / dock: Use ACPI device object pointers instead of ACPI handles
  ACPI / hotplug: Add .fixup() callback to struct acpi_hotplug_context
  ACPI / hotplug / PCI: Do not clear event callback pointer for docks
  ACPI / dock: Associate dock platform devices with ACPI device objects
  ACPI / dock: Pass ACPI device pointer to acpi_device_is_battery()
  ACPI / dock: Dispatch dock notifications from the global notify handler
parents d983f933 d901188f
...@@ -400,7 +400,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) ...@@ -400,7 +400,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK: case ACPI_NOTIFY_DEVICE_CHECK:
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
status = acpi_hotplug_execute(acpi_device_hotplug, adev, type); status = acpi_hotplug_schedule(adev, type);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
return; return;
default: default:
......
...@@ -68,6 +68,9 @@ static int container_device_attach(struct acpi_device *adev, ...@@ -68,6 +68,9 @@ static int container_device_attach(struct acpi_device *adev,
struct device *dev; struct device *dev;
int ret; int ret;
if (adev->flags.is_dock_station)
return 0;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev) if (!cdev)
return -ENOMEM; return -ENOMEM;
......
This diff is collapsed.
...@@ -37,9 +37,15 @@ void acpi_container_init(void); ...@@ -37,9 +37,15 @@ void acpi_container_init(void);
static inline void acpi_container_init(void) {} static inline void acpi_container_init(void) {}
#endif #endif
#ifdef CONFIG_ACPI_DOCK #ifdef CONFIG_ACPI_DOCK
void acpi_dock_init(void); void register_dock_dependent_device(struct acpi_device *adev,
acpi_handle dshandle);
int dock_notify(struct acpi_device *adev, u32 event);
void acpi_dock_add(struct acpi_device *adev);
#else #else
static inline void acpi_dock_init(void) {} static inline void register_dock_dependent_device(struct acpi_device *adev,
acpi_handle dshandle) {}
static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
static inline void acpi_dock_add(struct acpi_device *adev) {}
#endif #endif
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY #ifdef CONFIG_ACPI_HOTPLUG_MEMORY
void acpi_memory_hotplug_init(void); void acpi_memory_hotplug_init(void);
...@@ -72,8 +78,9 @@ void acpi_lpss_init(void); ...@@ -72,8 +78,9 @@ void acpi_lpss_init(void);
static inline void acpi_lpss_init(void) {} static inline void acpi_lpss_init(void) {}
#endif #endif
acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work); bool acpi_queue_hotplug_work(struct work_struct *work);
void acpi_device_hotplug(void *data, u32 src); void acpi_device_hotplug(struct acpi_device *adev, u32 src);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent); bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
...@@ -91,6 +98,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); ...@@ -91,6 +98,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
int acpi_bind_one(struct device *dev, struct acpi_device *adev); int acpi_bind_one(struct device *dev, struct acpi_device *adev);
int acpi_unbind_one(struct device *dev); int acpi_unbind_one(struct device *dev);
bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_present(struct acpi_device *adev);
bool acpi_device_is_battery(struct acpi_device *adev);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Power Resource Power Resource
......
...@@ -1168,8 +1168,7 @@ void acpi_os_wait_events_complete(void) ...@@ -1168,8 +1168,7 @@ void acpi_os_wait_events_complete(void)
struct acpi_hp_work { struct acpi_hp_work {
struct work_struct work; struct work_struct work;
acpi_hp_callback func; struct acpi_device *adev;
void *data;
u32 src; u32 src;
}; };
...@@ -1178,25 +1177,24 @@ static void acpi_hotplug_work_fn(struct work_struct *work) ...@@ -1178,25 +1177,24 @@ static void acpi_hotplug_work_fn(struct work_struct *work)
struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work); struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work);
acpi_os_wait_events_complete(); acpi_os_wait_events_complete();
hpw->func(hpw->data, hpw->src); acpi_device_hotplug(hpw->adev, hpw->src);
kfree(hpw); kfree(hpw);
} }
acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src) acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src)
{ {
struct acpi_hp_work *hpw; struct acpi_hp_work *hpw;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p, %u)] for deferred execution.\n", "Scheduling hotplug event (%p, %u) for deferred execution.\n",
func, data, src)); adev, src));
hpw = kmalloc(sizeof(*hpw), GFP_KERNEL); hpw = kmalloc(sizeof(*hpw), GFP_KERNEL);
if (!hpw) if (!hpw)
return AE_NO_MEMORY; return AE_NO_MEMORY;
INIT_WORK(&hpw->work, acpi_hotplug_work_fn); INIT_WORK(&hpw->work, acpi_hotplug_work_fn);
hpw->func = func; hpw->adev = adev;
hpw->data = data;
hpw->src = src; hpw->src = src;
/* /*
* We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because
......
...@@ -71,6 +71,17 @@ void acpi_unlock_hp_context(void) ...@@ -71,6 +71,17 @@ void acpi_unlock_hp_context(void)
mutex_unlock(&acpi_hp_context_lock); mutex_unlock(&acpi_hp_context_lock);
} }
void acpi_initialize_hp_context(struct acpi_device *adev,
struct acpi_hotplug_context *hp,
int (*notify)(struct acpi_device *, u32),
void (*uevent)(struct acpi_device *, u32))
{
acpi_lock_hp_context();
acpi_set_hp_context(adev, hp, notify, uevent, NULL);
acpi_unlock_hp_context();
}
EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
int acpi_scan_add_handler(struct acpi_scan_handler *handler) int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{ {
if (!handler || !handler->attach) if (!handler || !handler->attach)
...@@ -470,10 +481,9 @@ static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type) ...@@ -470,10 +481,9 @@ static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
return -EINVAL; return -EINVAL;
} }
void acpi_device_hotplug(void *data, u32 src) void acpi_device_hotplug(struct acpi_device *adev, u32 src)
{ {
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
struct acpi_device *adev = data;
int error = -ENODEV; int error = -ENODEV;
lock_device_hotplug(); lock_device_hotplug();
...@@ -487,24 +497,26 @@ void acpi_device_hotplug(void *data, u32 src) ...@@ -487,24 +497,26 @@ void acpi_device_hotplug(void *data, u32 src)
if (adev->handle == INVALID_ACPI_HANDLE) if (adev->handle == INVALID_ACPI_HANDLE)
goto err_out; goto err_out;
if (adev->flags.hotplug_notify) { if (adev->flags.is_dock_station) {
error = dock_notify(adev, src);
} else if (adev->flags.hotplug_notify) {
error = acpi_generic_hotplug_event(adev, src); error = acpi_generic_hotplug_event(adev, src);
if (error == -EPERM) { if (error == -EPERM) {
ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
goto err_out; goto err_out;
} }
} else { } else {
int (*event)(struct acpi_device *, u32); int (*notify)(struct acpi_device *, u32);
acpi_lock_hp_context(); acpi_lock_hp_context();
event = adev->hp ? adev->hp->event : NULL; notify = adev->hp ? adev->hp->notify : NULL;
acpi_unlock_hp_context(); acpi_unlock_hp_context();
/* /*
* There may be additional notify handlers for device objects * There may be additional notify handlers for device objects
* without the .event() callback, so ignore them here. * without the .event() callback, so ignore them here.
*/ */
if (event) if (notify)
error = event(adev, src); error = notify(adev, src);
else else
goto out; goto out;
} }
...@@ -566,8 +578,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr, ...@@ -566,8 +578,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
return -ENODEV; return -ENODEV;
get_device(&acpi_device->dev); get_device(&acpi_device->dev);
status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device, status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT);
ACPI_OST_EC_OSPM_EJECT);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
return count; return count;
...@@ -1660,6 +1671,27 @@ bool acpi_bay_match(acpi_handle handle) ...@@ -1660,6 +1671,27 @@ bool acpi_bay_match(acpi_handle handle)
return acpi_ata_match(phandle); return acpi_ata_match(phandle);
} }
bool acpi_device_is_battery(struct acpi_device *adev)
{
struct acpi_hardware_id *hwid;
list_for_each_entry(hwid, &adev->pnp.ids, list)
if (!strcmp("PNP0C0A", hwid->id))
return true;
return false;
}
static bool is_ejectable_bay(struct acpi_device *adev)
{
acpi_handle handle = adev->handle;
if (acpi_has_method(handle, "_EJ0") && acpi_device_is_battery(adev))
return true;
return acpi_bay_match(handle);
}
/* /*
* acpi_dock_match - see if an acpi object has a _DCK method * acpi_dock_match - see if an acpi object has a _DCK method
*/ */
...@@ -1964,6 +1996,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) ...@@ -1964,6 +1996,10 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
{ {
struct acpi_hardware_id *hwid; struct acpi_hardware_id *hwid;
if (acpi_dock_match(adev->handle) || is_ejectable_bay(adev)) {
acpi_dock_add(adev);
return;
}
list_for_each_entry(hwid, &adev->pnp.ids, list) { list_for_each_entry(hwid, &adev->pnp.ids, list) {
struct acpi_scan_handler *handler; struct acpi_scan_handler *handler;
...@@ -2035,8 +2071,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device) ...@@ -2035,8 +2071,12 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
static void acpi_bus_attach(struct acpi_device *device) static void acpi_bus_attach(struct acpi_device *device)
{ {
struct acpi_device *child; struct acpi_device *child;
acpi_handle ejd;
int ret; int ret;
if (ACPI_SUCCESS(acpi_bus_get_ejd(device->handle, &ejd)))
register_dock_dependent_device(device, ejd);
acpi_bus_get_status(device); acpi_bus_get_status(device);
/* Skip devices that are not present. */ /* Skip devices that are not present. */
if (!acpi_device_is_present(device)) { if (!acpi_device_is_present(device)) {
...@@ -2189,7 +2229,6 @@ int __init acpi_scan_init(void) ...@@ -2189,7 +2229,6 @@ int __init acpi_scan_init(void)
acpi_cmos_rtc_init(); acpi_cmos_rtc_init();
acpi_container_init(); acpi_container_init();
acpi_memory_hotplug_init(); acpi_memory_hotplug_init();
acpi_dock_init();
mutex_lock(&acpi_scan_lock); mutex_lock(&acpi_scan_lock);
/* /*
......
...@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev) ...@@ -38,6 +38,16 @@ static void ata_acpi_clear_gtf(struct ata_device *dev)
dev->gtf_cache = NULL; dev->gtf_cache = NULL;
} }
struct ata_acpi_hotplug_context {
struct acpi_hotplug_context hp;
union {
struct ata_port *ap;
struct ata_device *dev;
} data;
};
#define ata_hotplug_data(context) (container_of((context), struct ata_acpi_hotplug_context, hp)->data)
/** /**
* ata_dev_acpi_handle - provide the acpi_handle for an ata_device * ata_dev_acpi_handle - provide the acpi_handle for an ata_device
* @dev: the acpi_handle returned will correspond to this device * @dev: the acpi_handle returned will correspond to this device
...@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev, ...@@ -121,18 +131,17 @@ static void ata_acpi_handle_hotplug(struct ata_port *ap, struct ata_device *dev,
ata_port_wait_eh(ap); ata_port_wait_eh(ap);
} }
static void ata_acpi_dev_notify_dock(acpi_handle handle, u32 event, void *data) static int ata_acpi_dev_notify_dock(struct acpi_device *adev, u32 event)
{ {
struct ata_device *dev = data; struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_handle_hotplug(dev->link->ap, dev, event); ata_acpi_handle_hotplug(dev->link->ap, dev, event);
return 0;
} }
static void ata_acpi_ap_notify_dock(acpi_handle handle, u32 event, void *data) static int ata_acpi_ap_notify_dock(struct acpi_device *adev, u32 event)
{ {
struct ata_port *ap = data; ata_acpi_handle_hotplug(ata_hotplug_data(adev->hp).ap, NULL, event);
return 0;
ata_acpi_handle_hotplug(ap, NULL, event);
} }
static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
...@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev, ...@@ -154,31 +163,23 @@ static void ata_acpi_uevent(struct ata_port *ap, struct ata_device *dev,
} }
} }
static void ata_acpi_ap_uevent(acpi_handle handle, u32 event, void *data) static void ata_acpi_ap_uevent(struct acpi_device *adev, u32 event)
{ {
ata_acpi_uevent(data, NULL, event); ata_acpi_uevent(ata_hotplug_data(adev->hp).ap, NULL, event);
} }
static void ata_acpi_dev_uevent(acpi_handle handle, u32 event, void *data) static void ata_acpi_dev_uevent(struct acpi_device *adev, u32 event)
{ {
struct ata_device *dev = data; struct ata_device *dev = ata_hotplug_data(adev->hp).dev;
ata_acpi_uevent(dev->link->ap, dev, event); ata_acpi_uevent(dev->link->ap, dev, event);
} }
static const struct acpi_dock_ops ata_acpi_dev_dock_ops = {
.handler = ata_acpi_dev_notify_dock,
.uevent = ata_acpi_dev_uevent,
};
static const struct acpi_dock_ops ata_acpi_ap_dock_ops = {
.handler = ata_acpi_ap_notify_dock,
.uevent = ata_acpi_ap_uevent,
};
/* bind acpi handle to pata port */ /* bind acpi handle to pata port */
void ata_acpi_bind_port(struct ata_port *ap) void ata_acpi_bind_port(struct ata_port *ap)
{ {
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
struct acpi_device *adev;
struct ata_acpi_hotplug_context *context;
if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion)
return; return;
...@@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap) ...@@ -188,9 +189,17 @@ void ata_acpi_bind_port(struct ata_port *ap)
if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0)
ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; ap->pflags |= ATA_PFLAG_INIT_GTM_VALID;
/* we might be on a docking station */ adev = ACPI_COMPANION(&ap->tdev);
register_hotplug_dock_device(ACPI_HANDLE(&ap->tdev), if (!adev || adev->hp)
&ata_acpi_ap_dock_ops, ap, NULL, NULL); return;
context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context)
return;
context->data.ap = ap;
acpi_initialize_hp_context(adev, &context->hp, ata_acpi_ap_notify_dock,
ata_acpi_ap_uevent);
} }
void ata_acpi_bind_dev(struct ata_device *dev) void ata_acpi_bind_dev(struct ata_device *dev)
...@@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev) ...@@ -198,7 +207,8 @@ void ata_acpi_bind_dev(struct ata_device *dev)
struct ata_port *ap = dev->link->ap; struct ata_port *ap = dev->link->ap;
struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev);
struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev);
struct acpi_device *parent; struct acpi_device *parent, *adev;
struct ata_acpi_hotplug_context *context;
u64 adr; u64 adr;
/* /*
...@@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev) ...@@ -221,9 +231,17 @@ void ata_acpi_bind_dev(struct ata_device *dev)
} }
acpi_preset_companion(&dev->tdev, parent, adr); acpi_preset_companion(&dev->tdev, parent, adr);
adev = ACPI_COMPANION(&dev->tdev);
if (!adev || adev->hp)
return;
context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context)
return;
register_hotplug_dock_device(ata_dev_acpi_handle(dev), context->data.dev = dev;
&ata_acpi_dev_dock_ops, dev, NULL, NULL); acpi_initialize_hp_context(adev, &context->hp, ata_acpi_dev_notify_dock,
ata_acpi_dev_uevent);
} }
/** /**
......
...@@ -59,7 +59,8 @@ ...@@ -59,7 +59,8 @@
static LIST_HEAD(bridge_list); static LIST_HEAD(bridge_list);
static DEFINE_MUTEX(bridge_mutex); static DEFINE_MUTEX(bridge_mutex);
static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type); static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
static void acpiphp_post_dock_fixup(struct acpi_device *adev);
static void acpiphp_sanitize_bus(struct pci_bus *bus); static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus); static void acpiphp_set_hpp_values(struct pci_bus *bus);
static void hotplug_event(u32 type, struct acpiphp_context *context); static void hotplug_event(u32 type, struct acpiphp_context *context);
...@@ -80,7 +81,8 @@ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev) ...@@ -80,7 +81,8 @@ static struct acpiphp_context *acpiphp_init_context(struct acpi_device *adev)
return NULL; return NULL;
context->refcount = 1; context->refcount = 1;
acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_event); acpi_set_hp_context(adev, &context->hp, acpiphp_hotplug_notify, NULL,
acpiphp_post_dock_fixup);
return context; return context;
} }
...@@ -130,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge) ...@@ -130,6 +132,27 @@ static inline void put_bridge(struct acpiphp_bridge *bridge)
kref_put(&bridge->ref, free_bridge); kref_put(&bridge->ref, free_bridge);
} }
static struct acpiphp_context *acpiphp_grab_context(struct acpi_device *adev)
{
struct acpiphp_context *context;
acpi_lock_hp_context();
context = acpiphp_get_context(adev);
if (!context || context->func.parent->is_going_away) {
acpi_unlock_hp_context();
return NULL;
}
get_bridge(context->func.parent);
acpiphp_put_context(context);
acpi_unlock_hp_context();
return context;
}
static void acpiphp_let_context_go(struct acpiphp_context *context)
{
put_bridge(context->func.parent);
}
static void free_bridge(struct kref *kref) static void free_bridge(struct kref *kref)
{ {
struct acpiphp_context *context; struct acpiphp_context *context;
...@@ -164,28 +187,29 @@ static void free_bridge(struct kref *kref) ...@@ -164,28 +187,29 @@ static void free_bridge(struct kref *kref)
acpi_unlock_hp_context(); acpi_unlock_hp_context();
} }
/* /**
* the _DCK method can do funny things... and sometimes not * acpiphp_post_dock_fixup - Post-dock fixups for PCI devices.
* hah-hah funny. * @adev: ACPI device object corresponding to a PCI device.
* *
* TBD - figure out a way to only call fixups for * TBD - figure out a way to only call fixups for systems that require them.
* systems that require them.
*/ */
static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) static void acpiphp_post_dock_fixup(struct acpi_device *adev)
{ {
struct acpiphp_context *context = data; struct acpiphp_context *context = acpiphp_grab_context(adev);
struct pci_bus *bus = context->func.slot->bus; struct pci_bus *bus;
u32 buses; u32 buses;
if (!bus->self) if (!context)
return; return;
bus = context->func.slot->bus;
if (!bus->self)
goto out;
/* fixup bad _DCK function that rewrites /* fixup bad _DCK function that rewrites
* secondary bridge on slot * secondary bridge on slot
*/ */
pci_read_config_dword(bus->self, pci_read_config_dword(bus->self, PCI_PRIMARY_BUS, &buses);
PCI_PRIMARY_BUS,
&buses);
if (((buses >> 8) & 0xff) != bus->busn_res.start) { if (((buses >> 8) & 0xff) != bus->busn_res.start) {
buses = (buses & 0xff000000) buses = (buses & 0xff000000)
...@@ -194,24 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data) ...@@ -194,24 +218,11 @@ static void post_dock_fixups(acpi_handle not_used, u32 event, void *data)
| ((unsigned int)(bus->busn_res.end) << 16); | ((unsigned int)(bus->busn_res.end) << 16);
pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses); pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
} }
}
static void dock_event(acpi_handle handle, u32 type, void *data)
{
struct acpi_device *adev;
adev = acpi_bus_get_acpi_device(handle); out:
if (adev) { acpiphp_let_context_go(context);
acpiphp_hotplug_event(adev, type);
acpi_bus_put_acpi_device(adev);
}
} }
static const struct acpi_dock_ops acpiphp_dock_ops = {
.fixup = post_dock_fixups,
.handler = dock_event,
};
/* Check whether the PCI device is managed by native PCIe hotplug driver */ /* Check whether the PCI device is managed by native PCIe hotplug driver */
static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
{ {
...@@ -241,20 +252,6 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) ...@@ -241,20 +252,6 @@ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev)
return true; return true;
} }
static void acpiphp_dock_init(void *data)
{
struct acpiphp_context *context = data;
get_bridge(context->func.parent);
}
static void acpiphp_dock_release(void *data)
{
struct acpiphp_context *context = data;
put_bridge(context->func.parent);
}
/** /**
* acpiphp_add_context - Add ACPIPHP context to an ACPI device object. * acpiphp_add_context - Add ACPIPHP context to an ACPI device object.
* @handle: ACPI handle of the object to add a context to. * @handle: ACPI handle of the object to add a context to.
...@@ -300,22 +297,18 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, ...@@ -300,22 +297,18 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
newfunc = &context->func; newfunc = &context->func;
newfunc->function = function; newfunc->function = function;
newfunc->parent = bridge; newfunc->parent = bridge;
acpi_unlock_hp_context();
if (acpi_has_method(handle, "_EJ0")) /*
* If this is a dock device, its _EJ0 should be executed by the dock
* notify handler after calling _DCK.
*/
if (!is_dock_device(adev) && acpi_has_method(handle, "_EJ0"))
newfunc->flags = FUNC_HAS_EJ0; newfunc->flags = FUNC_HAS_EJ0;
if (acpi_has_method(handle, "_STA")) if (acpi_has_method(handle, "_STA"))
newfunc->flags |= FUNC_HAS_STA; newfunc->flags |= FUNC_HAS_STA;
/*
* Dock stations' notify handler should be used for dock devices instead
* of the common one, so clear hp.event in their contexts.
*/
if (acpi_has_method(handle, "_DCK"))
context->hp.event = NULL;
acpi_unlock_hp_context();
/* search for objects that share the same slot */ /* search for objects that share the same slot */
list_for_each_entry(slot, &bridge->slots, node) list_for_each_entry(slot, &bridge->slots, node)
if (slot->device == device) if (slot->device == device)
...@@ -341,7 +334,7 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, ...@@ -341,7 +334,7 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
* by the native PCIe hotplug (PCIeHP), becuase that code is supposed to * by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
* expose slots to user space in those cases. * expose slots to user space in those cases.
*/ */
if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(handle)) if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
&& !(pdev && device_is_managed_by_native_pciehp(pdev))) { && !(pdev && device_is_managed_by_native_pciehp(pdev))) {
unsigned long long sun; unsigned long long sun;
int retval; int retval;
...@@ -376,18 +369,6 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, ...@@ -376,18 +369,6 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
&val, 60*1000)) &val, 60*1000))
slot->flags |= SLOT_ENABLED; slot->flags |= SLOT_ENABLED;
if (is_dock_device(handle)) {
/* we don't want to call this device's _EJ0
* because we want the dock notify handler
* to call it after it calls _DCK
*/
newfunc->flags &= ~FUNC_HAS_EJ0;
if (register_hotplug_dock_device(handle,
&acpiphp_dock_ops, context,
acpiphp_dock_init, acpiphp_dock_release))
pr_debug("failed to register dock device\n");
}
return AE_OK; return AE_OK;
} }
...@@ -418,11 +399,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) ...@@ -418,11 +399,9 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_for_each_entry(func, &slot->funcs, sibling) { list_for_each_entry(func, &slot->funcs, sibling) {
struct acpi_device *adev = func_to_acpi_device(func); struct acpi_device *adev = func_to_acpi_device(func);
if (is_dock_device(adev->handle))
unregister_hotplug_dock_device(adev->handle);
acpi_lock_hp_context(); acpi_lock_hp_context();
adev->hp->event = NULL; adev->hp->notify = NULL;
adev->hp->fixup = NULL;
acpi_unlock_hp_context(); acpi_unlock_hp_context();
} }
slot->flags |= SLOT_IS_GOING_AWAY; slot->flags |= SLOT_IS_GOING_AWAY;
...@@ -851,23 +830,16 @@ static void hotplug_event(u32 type, struct acpiphp_context *context) ...@@ -851,23 +830,16 @@ static void hotplug_event(u32 type, struct acpiphp_context *context)
put_bridge(bridge); put_bridge(bridge);
} }
static int acpiphp_hotplug_event(struct acpi_device *adev, u32 type) static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type)
{ {
struct acpiphp_context *context; struct acpiphp_context *context;
acpi_lock_hp_context(); context = acpiphp_grab_context(adev);
context = acpiphp_get_context(adev); if (!context)
if (!context || context->func.parent->is_going_away) {
acpi_unlock_hp_context();
return -ENODATA; return -ENODATA;
}
get_bridge(context->func.parent);
acpiphp_put_context(context);
acpi_unlock_hp_context();
hotplug_event(type, context); hotplug_event(type, context);
acpiphp_let_context_go(context);
put_bridge(context->func.parent);
return 0; return 0;
} }
......
...@@ -143,7 +143,9 @@ struct acpi_scan_handler { ...@@ -143,7 +143,9 @@ struct acpi_scan_handler {
struct acpi_hotplug_context { struct acpi_hotplug_context {
struct acpi_device *self; struct acpi_device *self;
int (*event)(struct acpi_device *, u32); int (*notify)(struct acpi_device *, u32);
void (*uevent)(struct acpi_device *, u32);
void (*fixup)(struct acpi_device *);
}; };
/* /*
...@@ -201,7 +203,8 @@ struct acpi_device_flags { ...@@ -201,7 +203,8 @@ struct acpi_device_flags {
u32 visited:1; u32 visited:1;
u32 no_hotplug:1; u32 no_hotplug:1;
u32 hotplug_notify:1; u32 hotplug_notify:1;
u32 reserved:23; u32 is_dock_station:1;
u32 reserved:22;
}; };
/* File System */ /* File System */
...@@ -365,13 +368,22 @@ static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta) ...@@ -365,13 +368,22 @@ static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta)
static inline void acpi_set_hp_context(struct acpi_device *adev, static inline void acpi_set_hp_context(struct acpi_device *adev,
struct acpi_hotplug_context *hp, struct acpi_hotplug_context *hp,
int (*event)(struct acpi_device *, u32)) int (*notify)(struct acpi_device *, u32),
void (*uevent)(struct acpi_device *, u32),
void (*fixup)(struct acpi_device *))
{ {
hp->self = adev; hp->self = adev;
hp->event = event; hp->notify = notify;
hp->uevent = uevent;
hp->fixup = fixup;
adev->hp = hp; adev->hp = hp;
} }
void acpi_initialize_hp_context(struct acpi_device *adev,
struct acpi_hotplug_context *hp,
int (*notify)(struct acpi_device *, u32),
void (*uevent)(struct acpi_device *, u32));
/* acpi_device.dev.bus == &acpi_bus_type */ /* acpi_device.dev.bus == &acpi_bus_type */
extern struct bus_type acpi_bus_type; extern struct bus_type acpi_bus_type;
...@@ -443,10 +455,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev) ...@@ -443,10 +455,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
return adev && adev->flags.initialized && adev->flags.visited; return adev && adev->flags.initialized && adev->flags.visited;
} }
typedef void (*acpi_hp_callback)(void *data, u32 src);
acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src);
/** /**
* module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
* @__acpi_driver: acpi_driver struct * @__acpi_driver: acpi_driver struct
......
...@@ -109,36 +109,14 @@ void pci_acpi_crs_quirks(void); ...@@ -109,36 +109,14 @@ void pci_acpi_crs_quirks(void);
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
Dock Station Dock Station
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
struct acpi_dock_ops {
acpi_notify_handler fixup;
acpi_notify_handler handler;
acpi_notify_handler uevent;
};
#ifdef CONFIG_ACPI_DOCK #ifdef CONFIG_ACPI_DOCK
extern int is_dock_device(acpi_handle handle); extern int is_dock_device(struct acpi_device *adev);
extern int register_hotplug_dock_device(acpi_handle handle,
const struct acpi_dock_ops *ops,
void *context,
void (*init)(void *),
void (*release)(void *));
extern void unregister_hotplug_dock_device(acpi_handle handle);
#else #else
static inline int is_dock_device(acpi_handle handle) static inline int is_dock_device(struct acpi_device *adev)
{ {
return 0; return 0;
} }
static inline int register_hotplug_dock_device(acpi_handle handle,
const struct acpi_dock_ops *ops,
void *context,
void (*init)(void *),
void (*release)(void *))
{
return -ENODEV;
}
static inline void unregister_hotplug_dock_device(acpi_handle handle)
{
}
#endif /* CONFIG_ACPI_DOCK */ #endif /* CONFIG_ACPI_DOCK */
#endif /*__ACPI_DRIVERS_H__*/ #endif /*__ACPI_DRIVERS_H__*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment