Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ACPI] Bind PCI devices with ACPI devices

Implement the framework for binding physical devices
with ACPI devices. A physical bus like PCI bus
should create a 'acpi_bus_type', with:

.find_device:
For device which has parent such as normal PCI devices.

.find_bridge:
It's for special devices, such as PCI root bridge
or IDE controller. Such devices generally haven't a
parent or ->bus. We use the special method
to get an ACPI handle.

Uses new field in struct device: firmware_data

http://bugzilla.kernel.org/show_bug.cgi?id=4277

Signed-off-by: David Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by

David Shaohua Li and committed by
Len Brown
4e10d12a fb9802fa

+390 -5
+1 -1
drivers/acpi/Makefile
··· 36 36 endif 37 37 38 38 obj-$(CONFIG_ACPI_BUS) += sleep/ 39 - obj-$(CONFIG_ACPI_BUS) += bus.o 39 + obj-$(CONFIG_ACPI_BUS) += bus.o glue.o 40 40 obj-$(CONFIG_ACPI_AC) += ac.o 41 41 obj-$(CONFIG_ACPI_BATTERY) += battery.o 42 42 obj-$(CONFIG_ACPI_BUTTON) += button.o
+362
drivers/acpi/glue.c
··· 1 + /* 2 + * Link physical devices with ACPI devices support 3 + * 4 + * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com> 5 + * Copyright (c) 2005 Intel Corp. 6 + * 7 + * This file is released under the GPLv2. 8 + */ 9 + #include <linux/init.h> 10 + #include <linux/list.h> 11 + #include <linux/device.h> 12 + #include <linux/rwsem.h> 13 + #include <linux/acpi.h> 14 + 15 + #define ACPI_GLUE_DEBUG 0 16 + #if ACPI_GLUE_DEBUG 17 + #define DBG(x...) printk(PREFIX x) 18 + #else 19 + #define DBG(x...) 20 + #endif 21 + static LIST_HEAD(bus_type_list); 22 + static DECLARE_RWSEM(bus_type_sem); 23 + 24 + int register_acpi_bus_type(struct acpi_bus_type *type) 25 + { 26 + if (acpi_disabled) 27 + return -ENODEV; 28 + if (type && type->bus && type->find_device) { 29 + down_write(&bus_type_sem); 30 + list_add_tail(&type->list, &bus_type_list); 31 + up_write(&bus_type_sem); 32 + DBG("ACPI bus type %s registered\n", type->bus->name); 33 + return 0; 34 + } 35 + return -ENODEV; 36 + } 37 + 38 + EXPORT_SYMBOL(register_acpi_bus_type); 39 + 40 + int unregister_acpi_bus_type(struct acpi_bus_type *type) 41 + { 42 + if (acpi_disabled) 43 + return 0; 44 + if (type) { 45 + down_write(&bus_type_sem); 46 + list_del_init(&type->list); 47 + up_write(&bus_type_sem); 48 + DBG("ACPI bus type %s unregistered\n", type->bus->name); 49 + return 0; 50 + } 51 + return -ENODEV; 52 + } 53 + 54 + EXPORT_SYMBOL(unregister_acpi_bus_type); 55 + 56 + static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) 57 + { 58 + struct acpi_bus_type *tmp, *ret = NULL; 59 + 60 + down_read(&bus_type_sem); 61 + list_for_each_entry(tmp, &bus_type_list, list) { 62 + if (tmp->bus == type) { 63 + ret = tmp; 64 + break; 65 + } 66 + } 67 + up_read(&bus_type_sem); 68 + return ret; 69 + } 70 + 71 + static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle) 72 + { 73 + struct acpi_bus_type *tmp; 74 + int ret = -ENODEV; 75 + 76 + down_read(&bus_type_sem); 77 + list_for_each_entry(tmp, &bus_type_list, list) { 78 + if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) { 79 + ret = 0; 80 + break; 81 + } 82 + } 83 + up_read(&bus_type_sem); 84 + return ret; 85 + } 86 + 87 + /* Get PCI root bridge's handle from its segment and bus number */ 88 + struct acpi_find_pci_root { 89 + unsigned int seg; 90 + unsigned int bus; 91 + acpi_handle handle; 92 + }; 93 + 94 + static acpi_status 95 + do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data) 96 + { 97 + int *busnr = (int *)data; 98 + struct acpi_resource_address64 address; 99 + 100 + if (resource->id != ACPI_RSTYPE_ADDRESS16 && 101 + resource->id != ACPI_RSTYPE_ADDRESS32 && 102 + resource->id != ACPI_RSTYPE_ADDRESS64) 103 + return AE_OK; 104 + 105 + acpi_resource_to_address64(resource, &address); 106 + if ((address.address_length > 0) && 107 + (address.resource_type == ACPI_BUS_NUMBER_RANGE)) 108 + *busnr = address.min_address_range; 109 + 110 + return AE_OK; 111 + } 112 + 113 + static int get_root_bridge_busnr(acpi_handle handle) 114 + { 115 + acpi_status status; 116 + int bus, bbn; 117 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 118 + 119 + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 120 + 121 + status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL, 122 + (unsigned long *)&bbn); 123 + if (status == AE_NOT_FOUND) { 124 + /* Assume bus = 0 */ 125 + printk(KERN_INFO PREFIX 126 + "Assume root bridge [%s] bus is 0\n", 127 + (char *)buffer.pointer); 128 + status = AE_OK; 129 + bbn = 0; 130 + } 131 + if (ACPI_FAILURE(status)) { 132 + bbn = -ENODEV; 133 + goto exit; 134 + } 135 + if (bbn > 0) 136 + goto exit; 137 + 138 + /* _BBN in some systems return 0 for all root bridges */ 139 + bus = -1; 140 + status = acpi_walk_resources(handle, METHOD_NAME__CRS, 141 + do_root_bridge_busnr_callback, &bus); 142 + /* If _CRS failed, we just use _BBN */ 143 + if (ACPI_FAILURE(status) || (bus == -1)) 144 + goto exit; 145 + /* We select _CRS */ 146 + if (bbn != bus) { 147 + printk(KERN_INFO PREFIX 148 + "_BBN and _CRS returns different value for %s. Select _CRS\n", 149 + (char *)buffer.pointer); 150 + bbn = bus; 151 + } 152 + exit: 153 + acpi_os_free(buffer.pointer); 154 + return bbn; 155 + } 156 + 157 + static acpi_status 158 + find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv) 159 + { 160 + struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context; 161 + unsigned long seg, bus; 162 + acpi_status status; 163 + int tmp; 164 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 165 + 166 + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 167 + 168 + status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg); 169 + if (status == AE_NOT_FOUND) { 170 + /* Assume seg = 0 */ 171 + printk(KERN_INFO PREFIX 172 + "Assume root bridge [%s] segment is 0\n", 173 + (char *)buffer.pointer); 174 + status = AE_OK; 175 + seg = 0; 176 + } 177 + if (ACPI_FAILURE(status)) { 178 + status = AE_CTRL_DEPTH; 179 + goto exit; 180 + } 181 + 182 + tmp = get_root_bridge_busnr(handle); 183 + if (tmp < 0) { 184 + printk(KERN_ERR PREFIX 185 + "Find root bridge failed for %s\n", 186 + (char *)buffer.pointer); 187 + status = AE_CTRL_DEPTH; 188 + goto exit; 189 + } 190 + bus = tmp; 191 + 192 + if (seg == find->seg && bus == find->bus) 193 + find->handle = handle; 194 + status = AE_OK; 195 + exit: 196 + acpi_os_free(buffer.pointer); 197 + return status; 198 + } 199 + 200 + acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) 201 + { 202 + struct acpi_find_pci_root find = { seg, bus, NULL }; 203 + 204 + acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL); 205 + return find.handle; 206 + } 207 + 208 + /* Get device's handler per its address under its parent */ 209 + struct acpi_find_child { 210 + acpi_handle handle; 211 + acpi_integer address; 212 + }; 213 + 214 + static acpi_status 215 + do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv) 216 + { 217 + acpi_status status; 218 + struct acpi_device_info *info; 219 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 220 + struct acpi_find_child *find = (struct acpi_find_child *)context; 221 + 222 + status = acpi_get_object_info(handle, &buffer); 223 + if (ACPI_SUCCESS(status)) { 224 + info = buffer.pointer; 225 + if (info->address == find->address) 226 + find->handle = handle; 227 + acpi_os_free(buffer.pointer); 228 + } 229 + return AE_OK; 230 + } 231 + 232 + acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address) 233 + { 234 + struct acpi_find_child find = { NULL, address }; 235 + 236 + if (!parent) 237 + return NULL; 238 + acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 239 + 1, do_acpi_find_child, &find, NULL); 240 + return find.handle; 241 + } 242 + 243 + EXPORT_SYMBOL(acpi_get_child); 244 + 245 + /* Link ACPI devices with physical devices */ 246 + static void acpi_glue_data_handler(acpi_handle handle, 247 + u32 function, void *context) 248 + { 249 + /* we provide an empty handler */ 250 + } 251 + 252 + /* Note: a success call will increase reference count by one */ 253 + struct device *acpi_get_physical_device(acpi_handle handle) 254 + { 255 + acpi_status status; 256 + struct device *dev; 257 + 258 + status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev); 259 + if (ACPI_SUCCESS(status)) 260 + return get_device(dev); 261 + return NULL; 262 + } 263 + 264 + EXPORT_SYMBOL(acpi_get_physical_device); 265 + 266 + static int acpi_bind_one(struct device *dev, acpi_handle handle) 267 + { 268 + acpi_status status; 269 + 270 + if (dev->firmware_data) { 271 + printk(KERN_WARNING PREFIX 272 + "Drivers changed 'firmware_data' for %s\n", dev->bus_id); 273 + return -EINVAL; 274 + } 275 + get_device(dev); 276 + status = acpi_attach_data(handle, acpi_glue_data_handler, dev); 277 + if (ACPI_FAILURE(status)) { 278 + put_device(dev); 279 + return -EINVAL; 280 + } 281 + dev->firmware_data = handle; 282 + 283 + return 0; 284 + } 285 + 286 + static int acpi_unbind_one(struct device *dev) 287 + { 288 + if (!dev->firmware_data) 289 + return 0; 290 + if (dev == acpi_get_physical_device(dev->firmware_data)) { 291 + /* acpi_get_physical_device increase refcnt by one */ 292 + put_device(dev); 293 + acpi_detach_data(dev->firmware_data, acpi_glue_data_handler); 294 + dev->firmware_data = NULL; 295 + /* acpi_bind_one increase refcnt by one */ 296 + put_device(dev); 297 + } else { 298 + printk(KERN_ERR PREFIX 299 + "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id); 300 + } 301 + return 0; 302 + } 303 + 304 + static int acpi_platform_notify(struct device *dev) 305 + { 306 + struct acpi_bus_type *type; 307 + acpi_handle handle; 308 + int ret = -EINVAL; 309 + 310 + if (!dev->bus || !dev->parent) { 311 + /* bridge devices genernally haven't bus or parent */ 312 + ret = acpi_find_bridge_device(dev, &handle); 313 + goto end; 314 + } 315 + type = acpi_get_bus_type(dev->bus); 316 + if (!type) { 317 + printk(KERN_INFO PREFIX "No ACPI bus support for %s\n", 318 + dev->bus_id); 319 + ret = -EINVAL; 320 + goto end; 321 + } 322 + if ((ret = type->find_device(dev, &handle)) != 0) 323 + printk(KERN_INFO PREFIX "Can't get handler for %s\n", 324 + dev->bus_id); 325 + end: 326 + if (!ret) 327 + acpi_bind_one(dev, handle); 328 + 329 + #if ACPI_GLUE_DEBUG 330 + if (!ret) { 331 + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 332 + 333 + acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer); 334 + DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer); 335 + acpi_os_free(buffer.pointer); 336 + } else 337 + DBG("Device %s -> No ACPI support\n", dev->bus_id); 338 + #endif 339 + 340 + return ret; 341 + } 342 + 343 + static int acpi_platform_notify_remove(struct device *dev) 344 + { 345 + acpi_unbind_one(dev); 346 + return 0; 347 + } 348 + 349 + static int __init init_acpi_device_notify(void) 350 + { 351 + if (acpi_disabled) 352 + return 0; 353 + if (platform_notify || platform_notify_remove) { 354 + printk(KERN_ERR PREFIX "Can't use platform_notify\n"); 355 + return 0; 356 + } 357 + platform_notify = acpi_platform_notify; 358 + platform_notify_remove = acpi_platform_notify_remove; 359 + return 0; 360 + } 361 + 362 + arch_initcall(init_acpi_device_notify);
+2 -2
drivers/acpi/ibm_acpi.c
··· 1025 1025 return 0; 1026 1026 } 1027 1027 1028 - static int device_add(struct acpi_device *device) 1028 + static int ibmacpi_device_add(struct acpi_device *device) 1029 1029 { 1030 1030 return 0; 1031 1031 } ··· 1043 1043 memset(ibm->driver, 0, sizeof(struct acpi_driver)); 1044 1044 sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name); 1045 1045 ibm->driver->ids = ibm->hid; 1046 - ibm->driver->ops.add = &device_add; 1046 + ibm->driver->ops.add = &ibmacpi_device_add; 1047 1047 1048 1048 ret = acpi_bus_register_driver(ibm->driver); 1049 1049 if (ret < 0) {
+21
include/acpi/acpi_bus.h
··· 336 336 int acpi_create_dir(struct acpi_device *); 337 337 void acpi_remove_dir(struct acpi_device *); 338 338 339 + 340 + /* 341 + * Bind physical devices with ACPI devices 342 + */ 343 + #include <linux/device.h> 344 + struct acpi_bus_type { 345 + struct list_head list; 346 + struct bus_type *bus; 347 + /* For general devices under the bus*/ 348 + int (*find_device)(struct device *, acpi_handle*); 349 + /* For bridges, such as PCI root bridge, IDE controller */ 350 + int (*find_bridge)(struct device *, acpi_handle *); 351 + }; 352 + int register_acpi_bus_type(struct acpi_bus_type *); 353 + int unregister_acpi_bus_type(struct acpi_bus_type *); 354 + struct device *acpi_get_physical_device(acpi_handle); 355 + /* helper */ 356 + acpi_handle acpi_get_child(acpi_handle, acpi_integer); 357 + acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); 358 + #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->firmware_data)) 359 + 339 360 #endif /*CONFIG_ACPI_BUS*/ 340 361 341 362 #endif /*__ACPI_BUS_H__*/
+4 -2
include/linux/device.h
··· 269 269 struct device_driver *driver; /* which driver has allocated this 270 270 device */ 271 271 void *driver_data; /* data private to the driver */ 272 - void *platform_data; /* Platform specific data (e.g. ACPI, 273 - BIOS data relevant to device) */ 272 + void *platform_data; /* Platform specific data, device 273 + core doesn't touch it */ 274 + void *firmware_data; /* Firmware specific data (e.g. ACPI, 275 + BIOS data),reserved for device core*/ 274 276 struct dev_pm_info power; 275 277 276 278 u64 *dma_mask; /* dma mask (if dma'able device) */