Skip to content

Commit

Permalink
Merge branch 'acpi-cleanup'
Browse files Browse the repository at this point in the history
* acpi-cleanup: (21 commits)
  ACPI / hotplug: Fix concurrency issues and memory leaks
  ACPI: Remove the use of CONFIG_ACPI_CONTAINER_MODULE
  ACPI / scan: Full transition to D3cold in acpi_device_unregister()
  ACPI / scan: Make acpi_bus_hot_remove_device() acquire the scan lock
  ACPI: Drop the container.h header file
  ACPI / Documentation: refer to correct file for acpi_platform_device_ids[] table
  ACPI / scan: Make container driver use struct acpi_scan_handler
  ACPI / scan: Remove useless #ifndef from acpi_eject_store()
  ACPI: Unbind ACPI drv when probe failed
  ACPI: sysfs eject support for ACPI scan handlers
  ACPI / scan: Follow priorities of IDs when matching scan handlers
  ACPI / PCI: pci_slot: replace printk(KERN_xxx) with pr_xxx()
  ACPI / dock: Fix acpi_bus_get_device() check in drivers/acpi/dock.c
  ACPI / scan: Clean up acpi_bus_get_parent()
  ACPI / platform: Use struct acpi_scan_handler for creating devices
  ACPI / PCI: Make PCI IRQ link driver use struct acpi_scan_handler
  ACPI / PCI: Make PCI root driver use struct acpi_scan_handler
  ACPI / scan: Introduce struct acpi_scan_handler
  ACPI / scan: Make scanning of fixed devices follow the general scheme
  ACPI: Drop device start operation that is not used
  ...
  • Loading branch information
Rafael J. Wysocki committed Feb 15, 2013
2 parents b34bf8e + 3757b94 commit e8f71df
Show file tree
Hide file tree
Showing 55 changed files with 535 additions and 423 deletions.
4 changes: 2 additions & 2 deletions Documentation/acpi/enumeration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ from ACPI tables.
Currently the kernel is not able to automatically determine from which ACPI
device it should make the corresponding platform device so we need to add
the ACPI device explicitly to acpi_platform_device_ids list defined in
drivers/acpi/scan.c. This limitation is only for the platform devices, SPI
and I2C devices are created automatically as described below.
drivers/acpi/acpi_platform.c. This limitation is only for the platform
devices, SPI and I2C devices are created automatically as described below.

SPI serial bus support
~~~~~~~~~~~~~~~~~~~~~~
Expand Down
77 changes: 77 additions & 0 deletions Documentation/acpi/scan_handlers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
ACPI Scan Handlers

Copyright (C) 2012, Intel Corporation
Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

During system initialization and ACPI-based device hot-add, the ACPI namespace
is scanned in search of device objects that generally represent various pieces
of hardware. This causes a struct acpi_device object to be created and
registered with the driver core for every device object in the ACPI namespace
and the hierarchy of those struct acpi_device objects reflects the namespace
layout (i.e. parent device objects in the namespace are represented by parent
struct acpi_device objects and analogously for their children). Those struct
acpi_device objects are referred to as "device nodes" in what follows, but they
should not be confused with struct device_node objects used by the Device Trees
parsing code (although their role is analogous to the role of those objects).

During ACPI-based device hot-remove device nodes representing pieces of hardware
being removed are unregistered and deleted.

The core ACPI namespace scanning code in drivers/acpi/scan.c carries out basic
initialization of device nodes, such as retrieving common configuration
information from the device objects represented by them and populating them with
appropriate data, but some of them require additional handling after they have
been registered. For example, if the given device node represents a PCI host
bridge, its registration should cause the PCI bus under that bridge to be
enumerated and PCI devices on that bus to be registered with the driver core.
Similarly, if the device node represents a PCI interrupt link, it is necessary
to configure that link so that the kernel can use it.

Those additional configuration tasks usually depend on the type of the hardware
component represented by the given device node which can be determined on the
basis of the device node's hardware ID (HID). They are performed by objects
called ACPI scan handlers represented by the following structure:

struct acpi_scan_handler {
const struct acpi_device_id *ids;
struct list_head list_node;
int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
void (*detach)(struct acpi_device *dev);
};

where ids is the list of IDs of device nodes the given handler is supposed to
take care of, list_node is the hook to the global list of ACPI scan handlers
maintained by the ACPI core and the .attach() and .detach() callbacks are
executed, respectively, after registration of new device nodes and before
unregistration of device nodes the handler attached to previously.

The namespace scanning function, acpi_bus_scan(), first registers all of the
device nodes in the given namespace scope with the driver core. Then, it tries
to match a scan handler against each of them using the ids arrays of the
available scan handlers. If a matching scan handler is found, its .attach()
callback is executed for the given device node. If that callback returns 1,
that means that the handler has claimed the device node and is now responsible
for carrying out any additional configuration tasks related to it. It also will
be responsible for preparing the device node for unregistration in that case.
The device node's handler field is then populated with the address of the scan
handler that has claimed it.

If the .attach() callback returns 0, it means that the device node is not
interesting to the given scan handler and may be matched against the next scan
handler in the list. If it returns a (negative) error code, that means that
the namespace scan should be terminated due to a serious error. The error code
returned should then reflect the type of the error.

The namespace trimming function, acpi_bus_trim(), first executes .detach()
callbacks from the scan handlers of all device nodes in the given namespace
scope (if they have scan handlers). Next, it unregisters all of the device
nodes in that scope.

ACPI scan handlers can be added to the list maintained by the ACPI core with the
help of the acpi_scan_add_handler() function taking a pointer to the new scan
handler as an argument. The order in which scan handlers are added to the list
is the order in which they are matched against device nodes during namespace
scans.

All scan handles must be added to the list before acpi_bus_scan() is run for the
first time and they cannot be removed from it.
2 changes: 1 addition & 1 deletion arch/ia64/hp/common/aml_nfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ static int aml_nfw_add(struct acpi_device *device)
return aml_nfw_add_global_handler();
}

static int aml_nfw_remove(struct acpi_device *device, int type)
static int aml_nfw_remove(struct acpi_device *device)
{
return aml_nfw_remove_global_handler();
}
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/platform/olpc/olpc-xo15-sci.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ static int xo15_sci_add(struct acpi_device *device)
return r;
}

static int xo15_sci_remove(struct acpi_device *device, int type)
static int xo15_sci_remove(struct acpi_device *device)
{
acpi_disable_gpe(NULL, xo15_sci_gpe);
acpi_remove_gpe_handler(NULL, xo15_sci_gpe, xo15_sci_gpe_handler);
Expand Down
2 changes: 1 addition & 1 deletion drivers/acpi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ config X86_PM_TIMER
systems require this timer.

config ACPI_CONTAINER
tristate "Container and Module Devices (EXPERIMENTAL)"
bool "Container and Module Devices (EXPERIMENTAL)"
depends on EXPERIMENTAL
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
help
Expand Down
4 changes: 2 additions & 2 deletions drivers/acpi/ac.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file);
#endif

static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type);
static int acpi_ac_remove(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);

static const struct acpi_device_id ac_device_ids[] = {
Expand Down Expand Up @@ -337,7 +337,7 @@ static int acpi_ac_resume(struct device *dev)
}
#endif

static int acpi_ac_remove(struct acpi_device *device, int type)
static int acpi_ac_remove(struct acpi_device *device)
{
struct acpi_ac *ac = NULL;

Expand Down
60 changes: 39 additions & 21 deletions drivers/acpi/acpi_memhotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ MODULE_LICENSE("GPL");
#define MEMORY_POWER_OFF_STATE 2

static int acpi_memory_device_add(struct acpi_device *device);
static int acpi_memory_device_remove(struct acpi_device *device, int type);
static int acpi_memory_device_remove(struct acpi_device *device);

static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
Expand Down Expand Up @@ -153,14 +153,16 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
return 0;
}

static int
acpi_memory_get_device(acpi_handle handle,
struct acpi_memory_device **mem_device)
static int acpi_memory_get_device(acpi_handle handle,
struct acpi_memory_device **mem_device)
{
struct acpi_device *device = NULL;
int result;
int result = 0;

if (!acpi_bus_get_device(handle, &device) && device)
acpi_scan_lock_acquire();

acpi_bus_get_device(handle, &device);
if (device)
goto end;

/*
Expand All @@ -169,23 +171,28 @@ acpi_memory_get_device(acpi_handle handle,
*/
result = acpi_bus_scan(handle);
if (result) {
acpi_handle_warn(handle, "Cannot add acpi bus\n");
return -EINVAL;
acpi_handle_warn(handle, "ACPI namespace scan failed\n");
result = -EINVAL;
goto out;
}
result = acpi_bus_get_device(handle, &device);
if (result) {
acpi_handle_warn(handle, "Missing device object\n");
return -EINVAL;
result = -EINVAL;
goto out;
}

end:
end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
dev_err(&device->dev, "driver data not found\n");
return -ENODEV;
result = -ENODEV;
goto out;
}

return 0;
out:
acpi_scan_lock_release();
return result;
}

static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
Expand Down Expand Up @@ -305,6 +312,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *device;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
acpi_status status;

switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
Expand All @@ -327,29 +335,40 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived EJECT REQUEST notification for device\n"));

status = AE_ERROR;
acpi_scan_lock_acquire();

if (acpi_bus_get_device(handle, &device)) {
acpi_handle_err(handle, "Device doesn't exist\n");
break;
goto unlock;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
acpi_handle_err(handle, "Driver Data is NULL\n");
break;
goto unlock;
}

ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
pr_err(PREFIX "No memory, dropping EJECT\n");
break;
goto unlock;
}

get_device(&device->dev);
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
(void *)ej_event);
/* The eject is carried out asynchronously. */
status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
ej_event);
if (ACPI_FAILURE(status)) {
put_device(&device->dev);
kfree(ej_event);
}

/* eject is performed asynchronously */
return;
unlock:
acpi_scan_lock_release();
if (ACPI_SUCCESS(status))
return;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
Expand All @@ -360,7 +379,6 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)

/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
return;
}

static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
Expand Down Expand Up @@ -415,7 +433,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
return result;
}

static int acpi_memory_device_remove(struct acpi_device *device, int type)
static int acpi_memory_device_remove(struct acpi_device *device)
{
struct acpi_memory_device *mem_device = NULL;
int result;
Expand Down
3 changes: 1 addition & 2 deletions drivers/acpi/acpi_pad.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,7 @@ static int acpi_pad_add(struct acpi_device *device)
return 0;
}

static int acpi_pad_remove(struct acpi_device *device,
int type)
static int acpi_pad_remove(struct acpi_device *device)
{
mutex_lock(&isolated_cpus_lock);
acpi_pad_idle_cpus(0);
Expand Down
59 changes: 48 additions & 11 deletions drivers/acpi/acpi_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@

ACPI_MODULE_NAME("platform");

/* Flags for acpi_create_platform_device */
#define ACPI_PLATFORM_CLK BIT(0)

/*
* The following ACPI IDs are known to be suitable for representing as
* platform devices.
*/
static const struct acpi_device_id acpi_platform_device_ids[] = {

{ "PNP0D40" },

/* Haswell LPSS devices */
{ "INT33C0", ACPI_PLATFORM_CLK },
{ "INT33C1", ACPI_PLATFORM_CLK },
{ "INT33C2", ACPI_PLATFORM_CLK },
{ "INT33C3", ACPI_PLATFORM_CLK },
{ "INT33C4", ACPI_PLATFORM_CLK },
{ "INT33C5", ACPI_PLATFORM_CLK },
{ "INT33C6", ACPI_PLATFORM_CLK },
{ "INT33C7", ACPI_PLATFORM_CLK },

{ }
};

static int acpi_create_platform_clks(struct acpi_device *adev)
{
static struct platform_device *pdev;
Expand All @@ -39,18 +63,18 @@ static int acpi_create_platform_clks(struct acpi_device *adev)
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
* @flags: ACPI_PLATFORM_* flags that affect the creation of the platform
* devices.
* @id: ACPI device ID used to match @adev.
*
* Check if the given @adev can be represented as a platform device and, if
* that's the case, create and register a platform device, populate its common
* resources and returns a pointer to it. Otherwise, return %NULL.
*
* Name of the platform device will be the same as @adev's.
*/
struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
unsigned long flags)
static int acpi_create_platform_device(struct acpi_device *adev,
const struct acpi_device_id *id)
{
unsigned long flags = id->driver_data;
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
Expand All @@ -59,25 +83,28 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
struct resource *resources;
int count;

if ((flags & ACPI_PLATFORM_CLK) && acpi_create_platform_clks(adev)) {
dev_err(&adev->dev, "failed to create clocks\n");
return NULL;
if (flags & ACPI_PLATFORM_CLK) {
int ret = acpi_create_platform_clks(adev);
if (ret) {
dev_err(&adev->dev, "failed to create clocks\n");
return ret;
}
}

/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
return NULL;
return 0;

INIT_LIST_HEAD(&resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (count <= 0)
return NULL;
return 0;

resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
if (!resources) {
dev_err(&adev->dev, "No memory for resources\n");
acpi_dev_free_resource_list(&resource_list);
return NULL;
return -ENOMEM;
}
count = 0;
list_for_each_entry(rentry, &resource_list, node)
Expand Down Expand Up @@ -123,5 +150,15 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
}

kfree(resources);
return pdev;
return 1;
}

static struct acpi_scan_handler platform_handler = {
.ids = acpi_platform_device_ids,
.attach = acpi_create_platform_device,
};

void __init acpi_platform_init(void)
{
acpi_scan_add_handler(&platform_handler);
}
2 changes: 1 addition & 1 deletion drivers/acpi/battery.c
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ static int acpi_battery_add(struct acpi_device *device)
return result;
}

static int acpi_battery_remove(struct acpi_device *device, int type)
static int acpi_battery_remove(struct acpi_device *device)
{
struct acpi_battery *battery = NULL;

Expand Down
Loading

0 comments on commit e8f71df

Please sign in to comment.