glue.c 9.0 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 10

#include <linux/acpi_iort.h>
11
#include <linux/export.h>
12 13 14
#include <linux/init.h>
#include <linux/list.h>
#include <linux/device.h>
15
#include <linux/slab.h>
16 17
#include <linux/rwsem.h>
#include <linux/acpi.h>
18
#include <linux/dma-mapping.h>
19
#include <linux/platform_device.h>
20

21 22
#include "internal.h"

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

37
#define PHYSICAL_NODE_STRING "physical_node"
38
#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
39

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

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);
63 64
		printk(KERN_INFO PREFIX "bus type %s unregistered\n",
		       type->name);
65 66 67 68
		return 0;
	}
	return -ENODEV;
}
69
EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
70

71
static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
72 73 74 75 76
{
	struct acpi_bus_type *tmp, *ret = NULL;

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

86 87 88
#define FIND_CHILD_MIN_SCORE	1
#define FIND_CHILD_MAX_SCORE	2

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

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

101 102
	if (check_children && list_empty(&adev->children))
		return -ENODEV;
103

104
	/*
105 106 107 108 109
	 * If the device has a _HID returning a valid ACPI/PNP device ID, it is
	 * better to make it look less attractive here, so that the other device
	 * with the same _ADR value (that may not have a valid device ID) can be
	 * matched going forward.  [This means a second spec violation in a row,
	 * so whatever we do here is best effort anyway.]
110
	 */
111
	return sta_present && !adev->pnp.type.platform_id ?
112
			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
113 114
}

115 116
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
					   u64 address, bool check_children)
117
{
118 119 120
	struct acpi_device *adev, *ret = NULL;
	int ret_score = 0;

121 122 123
	if (!parent)
		return NULL;

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 150 151 152 153 154 155 156 157 158 159 160
	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;
		}
161
	}
162
	return ret;
163
}
164
EXPORT_SYMBOL_GPL(acpi_find_child_device);
165

166 167 168 169 170 171 172 173 174
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);
}

175
int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
176
{
177
	struct acpi_device_physical_node *physical_node, *pn;
178 179 180
	char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
	struct list_head *physnode_list;
	unsigned int node_id;
181
	int retval = -EINVAL;
182

183
	if (has_acpi_companion(dev)) {
184
		if (acpi_dev) {
185
			dev_warn(dev, "ACPI companion already set\n");
186 187
			return -EINVAL;
		} else {
188
			acpi_dev = ACPI_COMPANION(dev);
189
		}
190
	}
191
	if (!acpi_dev)
192
		return -EINVAL;
193

194
	get_device(&acpi_dev->dev);
195
	get_device(dev);
196
	physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL);
197 198 199
	if (!physical_node) {
		retval = -ENOMEM;
		goto err;
200 201
	}

202
	mutex_lock(&acpi_dev->physical_node_lock);
203

204 205 206 207 208 209 210 211
	/*
	 * 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. */
212
		if (pn->dev == dev) {
213 214
			mutex_unlock(&acpi_dev->physical_node_lock);

215
			dev_warn(dev, "Already associated with ACPI node\n");
216
			kfree(physical_node);
217
			if (ACPI_COMPANION(dev) != acpi_dev)
218
				goto err;
219

220
			put_device(dev);
221
			put_device(&acpi_dev->dev);
222
			return 0;
223
		}
224 225 226 227
		if (pn->node_id == node_id) {
			physnode_list = &pn->node;
			node_id++;
		}
228 229
	}

230
	physical_node->node_id = node_id;
231
	physical_node->dev = dev;
232
	list_add(&physical_node->node, physnode_list);
233
	acpi_dev->physical_node_count++;
234

235
	if (!has_acpi_companion(dev))
236
		ACPI_COMPANION_SET(dev, acpi_dev);
237

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

245
	retval = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
246
				   "firmware_node");
247 248 249
	if (retval)
		dev_err(dev, "Failed to create link firmware_node (%d)\n",
			retval);
250

251 252
	mutex_unlock(&acpi_dev->physical_node_lock);

253 254 255
	if (acpi_dev->wakeup.flags.valid)
		device_set_wakeup_capable(dev, true);

256
	return 0;
257 258

 err:
259
	ACPI_COMPANION_SET(dev, NULL);
260
	put_device(dev);
261
	put_device(&acpi_dev->dev);
262
	return retval;
263
}
264
EXPORT_SYMBOL_GPL(acpi_bind_one);
265

266
int acpi_unbind_one(struct device *dev)
267
{
268
	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
269 270
	struct acpi_device_physical_node *entry;

271
	if (!acpi_dev)
272
		return 0;
273

274
	mutex_lock(&acpi_dev->physical_node_lock);
275 276 277 278 279 280 281 282 283 284 285

	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");
286
			ACPI_COMPANION_SET(dev, NULL);
287
			/* Drop references taken by acpi_bind_one(). */
288
			put_device(dev);
289
			put_device(&acpi_dev->dev);
290 291 292 293
			kfree(entry);
			break;
		}

294
	mutex_unlock(&acpi_dev->physical_node_lock);
295 296
	return 0;
}
297
EXPORT_SYMBOL_GPL(acpi_unbind_one);
298 299 300

static int acpi_platform_notify(struct device *dev)
{
301
	struct acpi_bus_type *type = acpi_get_bus_type(dev);
302
	struct acpi_device *adev;
303
	int ret;
304

305
	ret = acpi_bind_one(dev, NULL);
306
	if (ret && type) {
307 308 309 310
		struct acpi_device *adev;

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

323
	if (dev_is_platform(dev))
324 325
		acpi_configure_pmsi_domain(dev);

326 327
	if (type && type->setup)
		type->setup(dev);
328 329
	else if (adev->handler && adev->handler->bind)
		adev->handler->bind(dev);
330

331
 out:
332 333 334 335
#if ACPI_GLUE_DEBUG
	if (!ret) {
		struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };

336
		acpi_get_name(ACPI_HANDLE(dev), ACPI_FULL_PATHNAME, &buffer);
337
		DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer);
338
		kfree(buffer.pointer);
339
	} else
340
		DBG("Device %s -> No ACPI support\n", dev_name(dev));
341 342 343 344 345 346 347
#endif

	return ret;
}

static int acpi_platform_notify_remove(struct device *dev)
{
348
	struct acpi_device *adev = ACPI_COMPANION(dev);
349 350
	struct acpi_bus_type *type;

351 352 353
	if (!adev)
		return 0;

354
	type = acpi_get_bus_type(dev);
355 356
	if (type && type->cleanup)
		type->cleanup(dev);
357 358
	else if (adev->handler && adev->handler->unbind)
		adev->handler->unbind(dev);
359

360 361 362 363
	acpi_unbind_one(dev);
	return 0;
}

364
void __init init_acpi_device_notify(void)
365 366 367
{
	if (platform_notify || platform_notify_remove) {
		printk(KERN_ERR PREFIX "Can't use platform_notify\n");
368
		return;
369 370 371 372
	}
	platform_notify = acpi_platform_notify;
	platform_notify_remove = acpi_platform_notify_remove;
}