glue.c 8.6 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * Link physical devices with ACPI devices support
 *
 * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
 * Copyright (c) 2005 Intel Corp.
 *
 * This file is released under the GPLv2.
 */
9
#include <linux/export.h>
10 11 12
#include <linux/init.h>
#include <linux/list.h>
#include <linux/device.h>
13
#include <linux/slab.h>
14 15
#include <linux/rwsem.h>
#include <linux/acpi.h>
16
#include <linux/dma-mapping.h>
17

18 19
#include "internal.h"

20 21
#define ACPI_GLUE_DEBUG	0
#if ACPI_GLUE_DEBUG
22 23
#define DBG(fmt, ...)						\
	printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__)
24
#else
25 26 27 28 29
#define DBG(fmt, ...)						\
do {								\
	if (0)							\
		printk(KERN_DEBUG PREFIX fmt, ##__VA_ARGS__);	\
} while (0)
30 31 32 33
#endif
static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);

34
#define PHYSICAL_NODE_STRING "physical_node"
35
#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
36

37 38 39 40
int register_acpi_bus_type(struct acpi_bus_type *type)
{
	if (acpi_disabled)
		return -ENODEV;
41
	if (type && type->match && type->find_companion) {
42 43 44
		down_write(&bus_type_sem);
		list_add_tail(&type->list, &bus_type_list);
		up_write(&bus_type_sem);
45
		printk(KERN_INFO PREFIX "bus type %s registered\n", type->name);
46 47 48 49
		return 0;
	}
	return -ENODEV;
}
50
EXPORT_SYMBOL_GPL(register_acpi_bus_type);
51 52 53 54 55 56 57 58 59

int unregister_acpi_bus_type(struct acpi_bus_type *type)
{
	if (acpi_disabled)
		return 0;
	if (type) {
		down_write(&bus_type_sem);
		list_del_init(&type->list);
		up_write(&bus_type_sem);
60 61
		printk(KERN_INFO PREFIX "bus type %s unregistered\n",
		       type->name);
62 63 64 65
		return 0;
	}
	return -ENODEV;
}
66
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
67

68
static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
69 70 71 72 73
{
	struct acpi_bus_type *tmp, *ret = NULL;

	down_read(&bus_type_sem);
	list_for_each_entry(tmp, &bus_type_list, list) {
74
		if (tmp->match(dev)) {
75 76 77 78 79 80 81 82
			ret = tmp;
			break;
		}
	}
	up_read(&bus_type_sem);
	return ret;
}

83 84 85
#define FIND_CHILD_MIN_SCORE	1
#define FIND_CHILD_MAX_SCORE	2

86
static int find_child_checks(struct acpi_device *adev, bool check_children)
87
{
88
	bool sta_present = true;
89 90 91
	unsigned long long sta;
	acpi_status status;

92
	status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta);
93 94 95 96
	if (status == AE_NOT_FOUND)
		sta_present = false;
	else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
		return -ENODEV;
97

98 99
	if (check_children && list_empty(&adev->children))
		return -ENODEV;
100

101
	return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
102 103
}

104 105
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
					   u64 address, bool check_children)
106
{
107 108 109
	struct acpi_device *adev, *ret = NULL;
	int ret_score = 0;

110 111 112
	if (!parent)
		return NULL;

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
	list_for_each_entry(adev, &parent->children, node) {
		unsigned long long addr;
		acpi_status status;
		int score;

		status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR,
					       NULL, &addr);
		if (ACPI_FAILURE(status) || addr != address)
			continue;

		if (!ret) {
			/* This is the first matching object.  Save it. */
			ret = adev;
			continue;
		}
		/*
		 * There is more than one matching device object with the same
		 * _ADR value.  That really is unexpected, so we are kind of
		 * beyond the scope of the spec here.  We have to choose which
		 * one to return, though.
		 *
		 * First, check if the previously found object is good enough
		 * and return it if so.  Second, do the same for the object that
		 * we've just found.
		 */
		if (!ret_score) {
			ret_score = find_child_checks(ret, check_children);
			if (ret_score == FIND_CHILD_MAX_SCORE)
				return ret;
		}
		score = find_child_checks(adev, check_children);
		if (score == FIND_CHILD_MAX_SCORE) {
			return adev;
		} else if (score > ret_score) {
			ret = adev;
			ret_score = score;
		}
150
	}
151
	return ret;
152
}
153
EXPORT_SYMBOL_GPL(acpi_find_child_device);
154

155 156 157 158 159 160 161 162 163
static void acpi_physnode_link_name(char *buf, unsigned int node_id)
{
	if (node_id > 0)
		snprintf(buf, PHYSICAL_NODE_NAME_SIZE,
			 PHYSICAL_NODE_STRING "%u", node_id);
	else
		strcpy(buf, PHYSICAL_NODE_STRING);
}

164
int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
165
{
166
	struct acpi_device_physical_node *physical_node, *pn;
167 168 169
	char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
	struct list_head *physnode_list;
	unsigned int node_id;
170
	int retval = -EINVAL;
171
	enum dev_dma_attr attr;
172

173
	if (has_acpi_companion(dev)) {
174
		if (acpi_dev) {
175
			dev_warn(dev, "ACPI companion already set\n");
176 177
			return -EINVAL;
		} else {
178
			acpi_dev = ACPI_COMPANION(dev);
179
		}
180
	}
181
	if (!acpi_dev)
182
		return -EINVAL;
183

184
	get_device(&acpi_dev->dev);
185
	get_device(dev);
186
	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
187 188 189
	if (!physical_node) {
		retval = -ENOMEM;
		goto err;
190 191
	}

192
	mutex_lock(&acpi_dev->physical_node_lock);
193

194 195 196 197 198 199 200 201
	/*
	 * Keep the list sorted by node_id so that the IDs of removed nodes can
	 * be recycled easily.
	 */
	physnode_list = &acpi_dev->physical_node_list;
	node_id = 0;
	list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
		/* Sanity check. */
202
		if (pn->dev == dev) {
203 204
			mutex_unlock(&acpi_dev->physical_node_lock);

205
			dev_warn(dev, "Already associated with ACPI node\n");
206
			kfree(physical_node);
207
			if (ACPI_COMPANION(dev) != acpi_dev)
208
				goto err;
209

210
			put_device(dev);
211
			put_device(&acpi_dev->dev);
212
			return 0;
213
		}
214 215 216 217
		if (pn->node_id == node_id) {
			physnode_list = &pn->node;
			node_id++;
		}
218 219
	}

220
	physical_node->node_id = node_id;
221
	physical_node->dev = dev;
222
	list_add(&physical_node->node, physnode_list);
223
	acpi_dev->physical_node_count++;
224

225
	if (!has_acpi_companion(dev))
226
		ACPI_COMPANION_SET(dev, acpi_dev);
227

228 229
	attr = acpi_get_dma_attr(acpi_dev);
	if (attr != DEV_DMA_NOT_SUPPORTED)
230
		acpi_dma_configure(dev, attr);
231

232
	acpi_physnode_link_name(physical_node_name, node_id);
233
	retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
234
				   physical_node_name);
235 236 237 238
	if (retval)
		dev_err(&acpi_dev->dev, "Failed to create link %s (%d)\n",
			physical_node_name, retval);

239
	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
240
				   "firmware_node");
241 242 243
	if (retval)
		dev_err(dev, "Failed to create link firmware_node (%d)\n",
			retval);
244

245 246
	mutex_unlock(&acpi_dev->physical_node_lock);

247 248 249
	if (acpi_dev->wakeup.flags.valid)
		device_set_wakeup_capable(dev, true);

250
	return 0;
251 252

 err:
253
	ACPI_COMPANION_SET(dev, NULL);
254
	put_device(dev);
255
	put_device(&acpi_dev->dev);
256
	return retval;
257
}
258
EXPORT_SYMBOL_GPL(acpi_bind_one);
259

260
int acpi_unbind_one(struct device *dev)
261
{
262
	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
263 264
	struct acpi_device_physical_node *entry;

265
	if (!acpi_dev)
266
		return 0;
267

268
	mutex_lock(&acpi_dev->physical_node_lock);
269 270 271 272 273 274 275 276 277 278 279

	list_for_each_entry(entry, &acpi_dev->physical_node_list, node)
		if (entry->dev == dev) {
			char physnode_name[PHYSICAL_NODE_NAME_SIZE];

			list_del(&entry->node);
			acpi_dev->physical_node_count--;

			acpi_physnode_link_name(physnode_name, entry->node_id);
			sysfs_remove_link(&acpi_dev->dev.kobj, physnode_name);
			sysfs_remove_link(&dev->kobj, "firmware_node");
280
			ACPI_COMPANION_SET(dev, NULL);
281
			/* Drop references taken by acpi_bind_one(). */
282
			put_device(dev);
283
			put_device(&acpi_dev->dev);
284 285 286 287
			kfree(entry);
			break;
		}

288
	mutex_unlock(&acpi_dev->physical_node_lock);
289 290
	return 0;
}
291
EXPORT_SYMBOL_GPL(acpi_unbind_one);
292 293 294

static int acpi_platform_notify(struct device *dev)
{
295
	struct acpi_bus_type *type = acpi_get_bus_type(dev);
296
	struct acpi_device *adev;
297
	int ret;
298

299
	ret = acpi_bind_one(dev, NULL);
300
	if (ret && type) {
301 302 303 304
		struct acpi_device *adev;

		adev = type->find_companion(dev);
		if (!adev) {
305
			DBG("Unable to get handle for %s\n", dev_name(dev));
306
			ret = -ENODEV;
307 308
			goto out;
		}
309
		ret = acpi_bind_one(dev, adev);
310 311
		if (ret)
			goto out;
312
	}
313 314 315
	adev = ACPI_COMPANION(dev);
	if (!adev)
		goto out;
316 317 318

	if (type && type->setup)
		type->setup(dev);
319 320
	else if (adev->handler && adev->handler->bind)
		adev->handler->bind(dev);
321

322
 out:
323 324 325 326
#if ACPI_GLUE_DEBUG
	if (!ret) {
		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };

327
		acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
328
		DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
329
		kfree(buffer.pointer);
330
	} else
331
		DBG("Device %s -> No ACPI support\n", dev_name(dev));
332 333 334 335 336 337 338
#endif

	return ret;
}

static int acpi_platform_notify_remove(struct device *dev)
{
339
	struct acpi_device *adev = ACPI_COMPANION(dev);
340 341
	struct acpi_bus_type *type;

342 343 344
	if (!adev)
		return 0;

345
	type = acpi_get_bus_type(dev);
346 347
	if (type && type->cleanup)
		type->cleanup(dev);
348 349
	else if (adev->handler && adev->handler->unbind)
		adev->handler->unbind(dev);
350

351 352 353 354
	acpi_unbind_one(dev);
	return 0;
}

355
void __init init_acpi_device_notify(void)
356 357 358
{
	if (platform_notify || platform_notify_remove) {
		printk(KERN_ERR PREFIX "Can't use platform_notify\n");
359
		return;
360 361 362 363
	}
	platform_notify = acpi_platform_notify;
	platform_notify_remove = acpi_platform_notify_remove;
}