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
#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 102 103 104 105 106 107 108 109
	/*
	 * If the device has a _HID (or _CID) 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.]
	 */
	return sta_present && list_empty(&adev->pnp.ids) ?
			FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
110 111
}

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

118 119 120
	if (!parent)
		return NULL;

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

163 164 165 166 167 168 169 170 171
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);
}

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

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

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

200
	mutex_lock(&acpi_dev->physical_node_lock);
201

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

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

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

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

233
	if (!has_acpi_companion(dev))
234
		ACPI_COMPANION_SET(dev, acpi_dev);
235

236 237
	attr = acpi_get_dma_attr(acpi_dev);
	if (attr != DEV_DMA_NOT_SUPPORTED)
238
		acpi_dma_configure(dev, attr);
239

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

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

253 254
	mutex_unlock(&acpi_dev->physical_node_lock);

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

258
	return 0;
259 260

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

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

273
	if (!acpi_dev)
274
		return 0;
275

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

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

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

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

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

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

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

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

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

	return ret;
}

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

350 351 352
	if (!adev)
		return 0;

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

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

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