mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
Merge back ACPI bus type changes for 7.3
This commit is contained in:
commit
fba08739e9
|
|
@ -1,80 +0,0 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0
|
||||
.. include:: <isonum.txt>
|
||||
|
||||
=========================================
|
||||
Why using ACPI drivers is not a good idea
|
||||
=========================================
|
||||
|
||||
:Copyright: |copy| 2026, Intel Corporation
|
||||
|
||||
:Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
|
||||
|
||||
Even though binding drivers directly to struct acpi_device objects, also
|
||||
referred to as "ACPI device nodes", allows basic functionality to be provided
|
||||
at least in some cases, there are problems with it, related to general
|
||||
consistency, sysfs layout, power management operation ordering, and code
|
||||
cleanliness.
|
||||
|
||||
First of all, ACPI device nodes represent firmware entities rather than
|
||||
hardware and in many cases they provide auxiliary information on devices
|
||||
enumerated independently (like PCI devices or CPUs). It is therefore generally
|
||||
questionable to assign resources to them because the entities represented by
|
||||
them do not decode addresses in the memory or I/O address spaces and do not
|
||||
generate interrupts or similar (all of that is done by hardware).
|
||||
|
||||
Second, as a general rule, a struct acpi_device can only be a parent of another
|
||||
struct acpi_device. If that is not the case, the location of the child device
|
||||
in the device hierarchy is at least confusing and it may not be straightforward
|
||||
to identify the piece of hardware providing functionality represented by it.
|
||||
However, binding a driver directly to an ACPI device node may cause that to
|
||||
happen if the given driver registers input devices or wakeup sources under it,
|
||||
for example.
|
||||
|
||||
Next, using system suspend and resume callbacks directly on ACPI device nodes
|
||||
is also questionable because it may cause ordering problems to appear. Namely,
|
||||
ACPI device nodes are registered before enumerating hardware corresponding to
|
||||
them and they land on the PM list in front of the majority of other device
|
||||
objects. Consequently, the execution ordering of their PM callbacks may be
|
||||
different from what is generally expected. Also, in general, dependencies
|
||||
returned by _DEP objects do not affect ACPI device nodes themselves, but the
|
||||
"physical" devices associated with them, which potentially is one more source
|
||||
of inconsistency related to treating ACPI device nodes as "real" device
|
||||
representation.
|
||||
|
||||
All of the above means that binding drivers to ACPI device nodes should
|
||||
generally be avoided and so struct acpi_driver objects should not be used.
|
||||
|
||||
Moreover, a device ID is necessary to bind a driver directly to an ACPI device
|
||||
node, but device IDs are not generally associated with all of them. Some of
|
||||
them contain alternative information allowing the corresponding pieces of
|
||||
hardware to be identified, for example represented by an _ADR object return
|
||||
value, and device IDs are not used in those cases. In consequence, confusingly
|
||||
enough, binding an ACPI driver to an ACPI device node may even be impossible.
|
||||
|
||||
When that happens, the piece of hardware corresponding to the given ACPI device
|
||||
node is represented by another device object, like a struct pci_dev, and the
|
||||
ACPI device node is the "ACPI companion" of that device, accessible through its
|
||||
fwnode pointer used by the ACPI_COMPANION() macro. The ACPI companion holds
|
||||
additional information on the device configuration and possibly some "recipes"
|
||||
on device manipulation in the form of AML (ACPI Machine Language) bytecode
|
||||
provided by the platform firmware. Thus the role of the ACPI device node is
|
||||
similar to the role of a struct device_node on a system where Device Tree is
|
||||
used for platform description.
|
||||
|
||||
For consistency, this approach has been extended to the cases in which ACPI
|
||||
device IDs are used. Namely, in those cases, an additional device object is
|
||||
created to represent the piece of hardware corresponding to a given ACPI device
|
||||
node. By default, it is a platform device, but it may also be a PNP device, a
|
||||
CPU device, or another type of device, depending on what the given piece of
|
||||
hardware actually is. There are even cases in which multiple devices are
|
||||
"backed" or "accompanied" by one ACPI device node (e.g. ACPI device nodes
|
||||
corresponding to GPUs that may provide firmware interfaces for backlight
|
||||
brightness control in addition to GPU configuration information).
|
||||
|
||||
This means that it really should never be necessary to bind a driver directly to
|
||||
an ACPI device node because there is a "proper" device object representing the
|
||||
corresponding piece of hardware that can be bound to by a "proper" driver using
|
||||
the given ACPI device node as the device's ACPI companion. Thus, in principle,
|
||||
there is no reason to use ACPI drivers and if they all were replaced with other
|
||||
driver types (for example, platform drivers), some code could be dropped and
|
||||
some complexity would go away.
|
||||
|
|
@ -7,4 +7,3 @@ ACPI Support
|
|||
|
||||
linuxized-acpica
|
||||
scan_handlers
|
||||
acpi-drivers
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ static int acpi_osc_handshake(acpi_handle handle, const char *uuid_str,
|
|||
.length = bufsize * sizeof(u32),
|
||||
};
|
||||
struct acpi_buffer output;
|
||||
u32 *retbuf, test;
|
||||
u32 *retbuf, test, errors;
|
||||
guid_t guid;
|
||||
int ret, i;
|
||||
|
||||
|
|
@ -395,10 +395,18 @@ static int acpi_osc_handshake(acpi_handle handle, const char *uuid_str,
|
|||
* Clear the feature bits in capbuf[] that have not been acknowledged.
|
||||
* After that, capbuf[] contains the resultant feature mask.
|
||||
*/
|
||||
for (i = OSC_QUERY_DWORD + 1; i < bufsize; i++)
|
||||
for (i = OSC_QUERY_DWORD + 1, test = 0; i < bufsize; i++) {
|
||||
test |= capbuf[i] & ~retbuf[i];
|
||||
capbuf[i] &= retbuf[i];
|
||||
}
|
||||
|
||||
if (retbuf[OSC_QUERY_DWORD] & OSC_ERROR_MASK) {
|
||||
errors = retbuf[OSC_QUERY_DWORD] & OSC_ERROR_MASK;
|
||||
/*
|
||||
* Some platforms set OSC_CAPABILITIES_MASK_ERROR even though they
|
||||
* acknowledge all of the requested features, so avoid complaining in
|
||||
* those cases unless any other error bits are also set.
|
||||
*/
|
||||
if (errors && (test || errors != OSC_CAPABILITIES_MASK_ERROR)) {
|
||||
/*
|
||||
* Complain about the unexpected errors and print diagnostic
|
||||
* information related to them.
|
||||
|
|
@ -620,41 +628,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
|||
acpi_evaluate_ost(handle, type, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL);
|
||||
}
|
||||
|
||||
static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct acpi_device *device = data;
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver);
|
||||
|
||||
acpi_drv->ops.notify(device, event);
|
||||
}
|
||||
|
||||
static int acpi_device_install_notify_handler(struct acpi_device *device,
|
||||
struct acpi_driver *acpi_drv)
|
||||
{
|
||||
u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
|
||||
ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle, type,
|
||||
acpi_notify_device, device);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_device_remove_notify_handler(struct acpi_device *device,
|
||||
struct acpi_driver *acpi_drv)
|
||||
{
|
||||
u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
|
||||
ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
|
||||
|
||||
acpi_remove_notify_handler(device->handle, type,
|
||||
acpi_notify_device);
|
||||
|
||||
acpi_os_wait_events_complete();
|
||||
}
|
||||
|
||||
int acpi_dev_install_notify_handler(struct acpi_device *adev,
|
||||
u32 handler_type,
|
||||
acpi_notify_handler handler, void *context)
|
||||
|
|
@ -1121,57 +1094,13 @@ bool acpi_driver_match_device(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(acpi_driver_match_device);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
ACPI Driver Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* __acpi_bus_register_driver - register a driver with the ACPI bus
|
||||
* @driver: driver being registered
|
||||
* @owner: owning module/driver
|
||||
*
|
||||
* Registers a driver with the ACPI bus. Searches the namespace for all
|
||||
* devices that match the driver's criteria and binds. Returns zero for
|
||||
* success or a negative error status for failure.
|
||||
*/
|
||||
int __acpi_bus_register_driver(struct acpi_driver *driver, struct module *owner)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
driver->drv.name = driver->name;
|
||||
driver->drv.bus = &acpi_bus_type;
|
||||
driver->drv.owner = owner;
|
||||
|
||||
return driver_register(&driver->drv);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(__acpi_bus_register_driver);
|
||||
|
||||
/**
|
||||
* acpi_bus_unregister_driver - unregisters a driver with the ACPI bus
|
||||
* @driver: driver to unregister
|
||||
*
|
||||
* Unregisters a driver with the ACPI bus. Searches the namespace for all
|
||||
* devices that match the driver's criteria and unbinds.
|
||||
*/
|
||||
void acpi_bus_unregister_driver(struct acpi_driver *driver)
|
||||
{
|
||||
driver_unregister(&driver->drv);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_unregister_driver);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
ACPI Bus operations
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static int acpi_bus_match(struct device *dev, const struct device_driver *drv)
|
||||
{
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
const struct acpi_driver *acpi_drv = to_acpi_driver(drv);
|
||||
|
||||
return acpi_dev->flags.match_driver
|
||||
&& !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
|
||||
|
|
@ -1179,66 +1108,9 @@ static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *
|
|||
return __acpi_device_uevent_modalias(to_acpi_device(dev), env);
|
||||
}
|
||||
|
||||
static int acpi_device_probe(struct device *dev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
|
||||
int ret;
|
||||
|
||||
if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev))
|
||||
return -EINVAL;
|
||||
|
||||
if (!acpi_drv->ops.add)
|
||||
return -ENOSYS;
|
||||
|
||||
ret = acpi_drv->ops.add(acpi_dev);
|
||||
if (ret) {
|
||||
acpi_dev->driver_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("Driver [%s] successfully bound to device [%s]\n",
|
||||
acpi_drv->name, acpi_dev->pnp.bus_id);
|
||||
|
||||
if (acpi_drv->ops.notify) {
|
||||
ret = acpi_device_install_notify_handler(acpi_dev, acpi_drv);
|
||||
if (ret) {
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
|
||||
acpi_dev->driver_data = NULL;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("Found driver [%s] for device [%s]\n", acpi_drv->name,
|
||||
acpi_dev->pnp.bus_id);
|
||||
|
||||
get_device(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acpi_device_remove(struct device *dev)
|
||||
{
|
||||
struct acpi_device *acpi_dev = to_acpi_device(dev);
|
||||
struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
|
||||
|
||||
if (acpi_drv->ops.notify)
|
||||
acpi_device_remove_notify_handler(acpi_dev, acpi_drv);
|
||||
|
||||
if (acpi_drv->ops.remove)
|
||||
acpi_drv->ops.remove(acpi_dev);
|
||||
|
||||
acpi_dev->driver_data = NULL;
|
||||
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
const struct bus_type acpi_bus_type = {
|
||||
.name = "acpi",
|
||||
.match = acpi_bus_match,
|
||||
.probe = acpi_device_probe,
|
||||
.remove = acpi_device_remove,
|
||||
.uevent = acpi_device_uevent,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -954,7 +954,6 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
|
|||
INIT_LIST_HEAD(&resource->list_node);
|
||||
INIT_LIST_HEAD(&resource->dependents);
|
||||
device->power.state = ACPI_STATE_UNKNOWN;
|
||||
device->flags.match_driver = true;
|
||||
|
||||
/* Evaluate the object to get the system level and resource order. */
|
||||
status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
|
||||
|
|
|
|||
|
|
@ -273,13 +273,9 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p)
|
|||
}
|
||||
}
|
||||
|
||||
adev->flags.match_driver = false;
|
||||
if (handler) {
|
||||
if (handler->detach)
|
||||
handler->detach(adev);
|
||||
} else {
|
||||
device_release_driver(&adev->dev);
|
||||
}
|
||||
if (handler && handler->detach)
|
||||
handler->detach(adev);
|
||||
|
||||
/*
|
||||
* Most likely, the device is going away, so put it into D3cold before
|
||||
* that.
|
||||
|
|
@ -1815,13 +1811,13 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
|
|||
device->dev.release = release;
|
||||
device->dev.bus = &acpi_bus_type;
|
||||
device->dev.groups = acpi_groups;
|
||||
device_set_pm_not_required(&device->dev);
|
||||
fwnode_init(&device->fwnode, &acpi_device_fwnode_ops);
|
||||
acpi_set_device_status(device, ACPI_STA_DEFAULT);
|
||||
acpi_device_get_busid(device);
|
||||
acpi_set_pnp_ids(handle, &device->pnp, type);
|
||||
acpi_init_properties(device);
|
||||
acpi_bus_get_flags(device);
|
||||
device->flags.match_driver = false;
|
||||
device->flags.initialized = true;
|
||||
device->flags.enumeration_by_parent =
|
||||
acpi_device_enumeration_by_parent(device);
|
||||
|
|
@ -2375,16 +2371,11 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass)
|
|||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
device->flags.match_driver = true;
|
||||
if (ret > 0 && !device->flags.enumeration_by_parent) {
|
||||
acpi_device_set_enumerated(device);
|
||||
goto ok;
|
||||
}
|
||||
|
||||
ret = device_attach(&device->dev);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (device->pnp.type.platform_id || device->pnp.type.backlight ||
|
||||
device->flags.enumeration_by_parent)
|
||||
acpi_default_enumeration(device);
|
||||
|
|
|
|||
|
|
@ -108,7 +108,6 @@ enum acpi_bus_device_type {
|
|||
ACPI_BUS_DEVICE_TYPE_COUNT
|
||||
};
|
||||
|
||||
struct acpi_driver;
|
||||
struct acpi_device;
|
||||
|
||||
/*
|
||||
|
|
@ -158,32 +157,6 @@ struct acpi_hotplug_context {
|
|||
acpi_hp_fixup fixup;
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI Driver
|
||||
* -----------
|
||||
*/
|
||||
|
||||
typedef int (*acpi_op_add) (struct acpi_device * device);
|
||||
typedef void (*acpi_op_remove) (struct acpi_device *device);
|
||||
typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event);
|
||||
|
||||
struct acpi_device_ops {
|
||||
acpi_op_add add;
|
||||
acpi_op_remove remove;
|
||||
acpi_op_notify notify;
|
||||
};
|
||||
|
||||
#define ACPI_DRIVER_ALL_NOTIFY_EVENTS 0x1 /* system AND device events */
|
||||
|
||||
struct acpi_driver {
|
||||
char name[80];
|
||||
char class[80];
|
||||
const struct acpi_device_id *ids; /* Supported Hardware IDs */
|
||||
unsigned int flags;
|
||||
struct acpi_device_ops ops;
|
||||
struct device_driver drv;
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI Device
|
||||
* -----------
|
||||
|
|
@ -211,7 +184,6 @@ struct acpi_device_flags {
|
|||
u32 removable:1;
|
||||
u32 ejectable:1;
|
||||
u32 power_manageable:1;
|
||||
u32 match_driver:1;
|
||||
u32 initialized:1;
|
||||
u32 visited:1;
|
||||
u32 hotplug_notify:1;
|
||||
|
|
@ -221,7 +193,7 @@ struct acpi_device_flags {
|
|||
u32 cca_seen:1;
|
||||
u32 enumeration_by_parent:1;
|
||||
u32 honor_deps:1;
|
||||
u32 reserved:18;
|
||||
u32 reserved:19;
|
||||
};
|
||||
|
||||
/* File System */
|
||||
|
|
@ -438,7 +410,7 @@ enum acpi_device_swnode_ep_props {
|
|||
* @lane_polarities: "lane-polarities" property values.
|
||||
* @link_frequencies: "link_frequencies" property values.
|
||||
* @port_nr: Port number.
|
||||
* @crs_crs2_local: _CRS CSI2 record present (i.e. this is a transmitter one).
|
||||
* @crs_csi2_local: _CRS CSI2 record present (i.e. this is a transmitter one).
|
||||
* @port_props: Port properties.
|
||||
* @ep_props: Endpoint properties.
|
||||
* @remote_ep: Reference to the remote endpoint.
|
||||
|
|
@ -461,7 +433,7 @@ struct acpi_device_software_node_port {
|
|||
* struct acpi_device_software_nodes - Software nodes for an ACPI device
|
||||
* @dev_props: Device properties.
|
||||
* @nodes: Software nodes for root as well as ports and endpoints.
|
||||
* @nodeprts: Array of software node pointers, for (un)registering them.
|
||||
* @nodeptrs: Array of software node pointers, for (un)registering them.
|
||||
* @ports: Information related to each port and endpoint within a port.
|
||||
* @num_ports: The number of ports.
|
||||
*/
|
||||
|
|
@ -570,7 +542,6 @@ static inline void *acpi_driver_data(struct acpi_device *d)
|
|||
}
|
||||
|
||||
#define to_acpi_device(d) container_of(d, struct acpi_device, dev)
|
||||
#define to_acpi_driver(d) container_of_const(d, struct acpi_driver, drv)
|
||||
|
||||
static inline struct acpi_device *acpi_dev_parent(struct acpi_device *adev)
|
||||
{
|
||||
|
|
@ -676,13 +647,6 @@ void acpi_scan_lock_release(void);
|
|||
void acpi_lock_hp_context(void);
|
||||
void acpi_unlock_hp_context(void);
|
||||
int acpi_scan_add_handler(struct acpi_scan_handler *handler);
|
||||
/*
|
||||
* use a macro to avoid include chaining to get THIS_MODULE
|
||||
*/
|
||||
#define acpi_bus_register_driver(drv) \
|
||||
__acpi_bus_register_driver(drv, THIS_MODULE)
|
||||
int __acpi_bus_register_driver(struct acpi_driver *driver, struct module *owner);
|
||||
void acpi_bus_unregister_driver(struct acpi_driver *driver);
|
||||
int acpi_bus_scan(acpi_handle handle);
|
||||
void acpi_bus_trim(struct acpi_device *start);
|
||||
acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
|
||||
|
|
@ -696,18 +660,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev)
|
|||
return adev && adev->flags.initialized && adev->flags.visited;
|
||||
}
|
||||
|
||||
/**
|
||||
* module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver
|
||||
* @__acpi_driver: acpi_driver struct
|
||||
*
|
||||
* Helper macro for ACPI drivers which do not do anything special in module
|
||||
* init/exit. This eliminates a lot of boilerplate. Each module may only
|
||||
* use this macro once, and calling it replaces module_init() and module_exit()
|
||||
*/
|
||||
#define module_acpi_driver(__acpi_driver) \
|
||||
module_driver(__acpi_driver, acpi_bus_register_driver, \
|
||||
acpi_bus_unregister_driver)
|
||||
|
||||
/*
|
||||
* Bind physical devices with ACPI devices
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user