Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2bd74d91 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'acpi-pci-hotplug' into acpi-ost

parents ae3caa80 cc6254e0
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -923,19 +923,22 @@ ACPI_EXPORT_SYMBOL(acpi_detach_data)

/*******************************************************************************
 *
 * FUNCTION:    acpi_get_data
 * FUNCTION:    acpi_get_data_full
 *
 * PARAMETERS:  obj_handle          - Namespace node
 *              handler             - Handler used in call to attach_data
 *              data                - Where the data is returned
 *              callback            - function to execute before returning
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
 * DESCRIPTION: Retrieve data that was previously attached to a namespace node
 *              and execute a callback before returning.
 *
 ******************************************************************************/
acpi_status
acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
acpi_get_data_full(acpi_handle obj_handle, acpi_object_handler handler,
		   void **data, void (*callback)(void *))
{
	struct acpi_namespace_node *node;
	acpi_status status;
@@ -960,10 +963,34 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
	}

	status = acpi_ns_get_attached_data(node, handler, data);
	if (ACPI_SUCCESS(status) && callback) {
		callback(*data);
	}

unlock_and_exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
	return (status);
}

ACPI_EXPORT_SYMBOL(acpi_get_data_full)

/*******************************************************************************
 *
 * FUNCTION:    acpi_get_data
 *
 * PARAMETERS:  obj_handle          - Namespace node
 *              handler             - Handler used in call to attach_data
 *              data                - Where the data is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
 *
 ******************************************************************************/
acpi_status
acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
{
	return acpi_get_data_full(obj_handle, handler, data, NULL);
}

ACPI_EXPORT_SYMBOL(acpi_get_data)
+39 −22
Original line number Diff line number Diff line
@@ -340,60 +340,77 @@ static void acpi_bus_osc_support(void)
 */
static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
	struct acpi_device *device = NULL;
	struct acpi_device *adev;
	struct acpi_driver *driver;

	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notification %#02x to handle %p\n",
			  type, handle));
	acpi_status status;
	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;

	switch (type) {

	case ACPI_NOTIFY_BUS_CHECK:
		/* TBD */
		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
		break;

	case ACPI_NOTIFY_DEVICE_CHECK:
		/* TBD */
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
		break;

	case ACPI_NOTIFY_DEVICE_WAKE:
		/* TBD */
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_WAKE event\n");
		break;

	case ACPI_NOTIFY_EJECT_REQUEST:
		/* TBD */
		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
		break;

	case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK_LIGHT event\n");
		/* TBD: Exactly what does 'light' mean? */
		break;

	case ACPI_NOTIFY_FREQUENCY_MISMATCH:
		/* TBD */
		acpi_handle_err(handle, "Device cannot be configured due "
				"to a frequency mismatch\n");
		break;

	case ACPI_NOTIFY_BUS_MODE_MISMATCH:
		/* TBD */
		acpi_handle_err(handle, "Device cannot be configured due "
				"to a bus mode mismatch\n");
		break;

	case ACPI_NOTIFY_POWER_FAULT:
		/* TBD */
		acpi_handle_err(handle, "Device has suffered a power fault\n");
		break;

	default:
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Received unknown/unsupported notification [%08x]\n",
				  type));
		break;
		acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
		ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
		goto err;
	}

	acpi_bus_get_device(handle, &device);
	if (device) {
		driver = device->driver;
	adev = acpi_bus_get_acpi_device(handle);
	if (!adev)
		goto err;

	driver = adev->driver;
	if (driver && driver->ops.notify &&
	    (driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
			driver->ops.notify(device, type);
		driver->ops.notify(adev, type);

	switch (type) {
	case ACPI_NOTIFY_BUS_CHECK:
	case ACPI_NOTIFY_DEVICE_CHECK:
	case ACPI_NOTIFY_EJECT_REQUEST:
		status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
		if (ACPI_SUCCESS(status))
			return;
	default:
		break;
	}
	acpi_bus_put_acpi_device(adev);
	return;

 err:
	acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
}

/* --------------------------------------------------------------------------
+1 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static inline void acpi_lpss_init(void) {}
#endif

bool acpi_queue_hotplug_work(struct work_struct *work);
void acpi_device_hotplug(void *data, u32 src);
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent);

/* --------------------------------------------------------------------------
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ static void acpi_pci_root_remove(struct acpi_device *device);

static int acpi_pci_root_scan_dependent(struct acpi_device *adev)
{
	acpiphp_check_host_bridge(adev->handle);
	acpiphp_check_host_bridge(adev);
	return 0;
}

+93 −88
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
static DEFINE_MUTEX(acpi_hp_context_lock);

struct acpi_device_bus_id{
	char bus_id[15];
@@ -60,6 +61,16 @@ void acpi_scan_lock_release(void)
}
EXPORT_SYMBOL_GPL(acpi_scan_lock_release);

void acpi_lock_hp_context(void)
{
	mutex_lock(&acpi_hp_context_lock);
}

void acpi_unlock_hp_context(void)
{
	mutex_unlock(&acpi_hp_context_lock);
}

int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{
	if (!handler || !handler->attach)
@@ -439,90 +450,74 @@ static int acpi_scan_bus_check(struct acpi_device *adev)
	return 0;
}

static void acpi_device_hotplug(void *data, u32 src)
static int acpi_generic_hotplug_event(struct acpi_device *adev, u32 type)
{
	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
	struct acpi_device *adev = data;
	int error;

	lock_device_hotplug();
	mutex_lock(&acpi_scan_lock);

	/*
	 * The device object's ACPI handle cannot become invalid as long as we
	 * are holding acpi_scan_lock, but it may have become invalid before
	 * that lock was acquired.
	 */
	if (adev->handle == INVALID_ACPI_HANDLE)
		goto out;

	switch (src) {
	switch (type) {
	case ACPI_NOTIFY_BUS_CHECK:
		error = acpi_scan_bus_check(adev);
		break;
		return acpi_scan_bus_check(adev);
	case ACPI_NOTIFY_DEVICE_CHECK:
		error = acpi_scan_device_check(adev);
		break;
		return acpi_scan_device_check(adev);
	case ACPI_NOTIFY_EJECT_REQUEST:
	case ACPI_OST_EC_OSPM_EJECT:
		error = acpi_scan_hot_remove(adev);
		break;
	default:
		error = -EINVAL;
		break;
		if (adev->handler && !adev->handler->hotplug.enabled) {
			dev_info(&adev->dev, "Eject disabled\n");
			return -EPERM;
		}
	if (!error)
		ost_code = ACPI_OST_SC_SUCCESS;

 out:
	acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);
	put_device(&adev->dev);
	mutex_unlock(&acpi_scan_lock);
	unlock_device_hotplug();
		acpi_evaluate_hotplug_ost(adev->handle, ACPI_NOTIFY_EJECT_REQUEST,
					  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
		return acpi_scan_hot_remove(adev);
	}
	return -EINVAL;
}

static void acpi_hotplug_notify_cb(acpi_handle handle, u32 type, void *data)
void acpi_device_hotplug(void *data, u32 src)
{
	u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
	struct acpi_device *adev;
	acpi_status status;
	struct acpi_device *adev = data;
	int error = -ENODEV;

	if (acpi_bus_get_device(handle, &adev))
		goto err_out;
	lock_device_hotplug();
	mutex_lock(&acpi_scan_lock);

	switch (type) {
	case ACPI_NOTIFY_BUS_CHECK:
		acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
		break;
	case ACPI_NOTIFY_DEVICE_CHECK:
		acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
		break;
	case ACPI_NOTIFY_EJECT_REQUEST:
		acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
		if (!adev->handler)
	/*
	 * The device object's ACPI handle cannot become invalid as long as we
	 * are holding acpi_scan_lock, but it might have become invalid before
	 * that lock was acquired.
	 */
	if (adev->handle == INVALID_ACPI_HANDLE)
		goto err_out;

		if (!adev->handler->hotplug.enabled) {
			acpi_handle_err(handle, "Eject disabled\n");
	if (adev->flags.hotplug_notify) {
		error = acpi_generic_hotplug_event(adev, src);
		if (error == -EPERM) {
			ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED;
			goto err_out;
		}
		acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST,
					  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
		break;
	default:
		/* non-hotplug event; possibly handled by other handler */
		return;
	}
	get_device(&adev->dev);
	status = acpi_hotplug_execute(acpi_device_hotplug, adev, type);
	if (ACPI_SUCCESS(status))
		return;
	} else {
		int (*event)(struct acpi_device *, u32);

	put_device(&adev->dev);
		acpi_lock_hp_context();
		event = adev->hp ? adev->hp->event : NULL;
		acpi_unlock_hp_context();
		/*
		 * There may be additional notify handlers for device objects
		 * without the .event() callback, so ignore them here.
		 */
		if (event)
			error = event(adev, src);
		else
			goto out;
	}
	if (!error)
		ost_code = ACPI_OST_SC_SUCCESS;

 err_out:
	acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
	acpi_evaluate_hotplug_ost(adev->handle, src, ost_code, NULL);

 out:
	acpi_bus_put_acpi_device(adev);
	mutex_unlock(&acpi_scan_lock);
	unlock_device_hotplug();
}

static ssize_t real_power_state_show(struct device *dev,
@@ -570,8 +565,6 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
	if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable)
		return -ENODEV;

	acpi_evaluate_hotplug_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT,
				  ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
	get_device(&acpi_device->dev);
	status = acpi_hotplug_execute(acpi_device_hotplug, acpi_device,
				      ACPI_OST_EC_OSPM_EJECT);
@@ -1114,14 +1107,16 @@ static void acpi_scan_drop_device(acpi_handle handle, void *context)
	mutex_unlock(&acpi_device_del_lock);
}

int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
static int acpi_get_device_data(acpi_handle handle, struct acpi_device **device,
				void (*callback)(void *))
{
	acpi_status status;

	if (!device)
		return -EINVAL;

	status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
	status = acpi_get_data_full(handle, acpi_scan_drop_device,
				    (void **)device, callback);
	if (ACPI_FAILURE(status) || !*device) {
		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
				  handle));
@@ -1129,8 +1124,32 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
	}
	return 0;
}

int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
{
	return acpi_get_device_data(handle, device, NULL);
}
EXPORT_SYMBOL(acpi_bus_get_device);

static void get_acpi_device(void *dev)
{
	if (dev)
		get_device(&((struct acpi_device *)dev)->dev);
}

struct acpi_device *acpi_bus_get_acpi_device(acpi_handle handle)
{
	struct acpi_device *adev = NULL;

	acpi_get_device_data(handle, &adev, get_acpi_device);
	return adev;
}

void acpi_bus_put_acpi_device(struct acpi_device *adev)
{
	put_device(&adev->dev);
}

int acpi_device_add(struct acpi_device *device,
		    void (*release)(struct device *))
{
@@ -1957,33 +1976,19 @@ void acpi_scan_hotplug_enabled(struct acpi_hotplug_profile *hotplug, bool val)
	mutex_unlock(&acpi_scan_lock);
}

static void acpi_scan_init_hotplug(acpi_handle handle, int type)
static void acpi_scan_init_hotplug(struct acpi_device *adev)
{
	struct acpi_device_pnp pnp = {};
	struct acpi_hardware_id *hwid;
	struct acpi_scan_handler *handler;

	INIT_LIST_HEAD(&pnp.ids);
	acpi_set_pnp_ids(handle, &pnp, type);

	if (!pnp.type.hardware_id)
		goto out;
	list_for_each_entry(hwid, &adev->pnp.ids, list) {
		struct acpi_scan_handler *handler;

	/*
	 * This relies on the fact that acpi_install_notify_handler() will not
	 * install the same notify handler routine twice for the same handle.
	 */
	list_for_each_entry(hwid, &pnp.ids, list) {
		handler = acpi_scan_match_handler(hwid->id, NULL);
		if (handler) {
			acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
					acpi_hotplug_notify_cb, handler);
			adev->flags.hotplug_notify = true;
			break;
		}
	}

out:
	acpi_free_pnp_ids(&pnp);
}

static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
@@ -2007,12 +2012,12 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
		return AE_OK;
	}

	acpi_scan_init_hotplug(handle, type);

	acpi_add_single_object(&device, handle, type, sta);
	if (!device)
		return AE_CTRL_DEPTH;

	acpi_scan_init_hotplug(device);

 out:
	if (!*return_value)
		*return_value = device;
Loading