diff options
author | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-02-10 14:45:43 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-02-10 14:45:43 -0500 |
commit | 81b7bbd1932a04869d4c8635a75222dfc6089f96 (patch) | |
tree | 285ae868a1e3a41fb0dbfe346c28e380949bcb55 /kernel | |
parent | 98051995ab44b993f992946055edc6115351f725 (diff) | |
parent | 66efc5a7e3061c3597ac43a8bb1026488d57e66b (diff) |
Merge branch 'linus'
Conflicts:
drivers/scsi/ipr.c
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/fork.c | 2 | ||||
-rw-r--r-- | kernel/irq/chip.c | 28 | ||||
-rw-r--r-- | kernel/irq/manage.c | 86 | ||||
-rw-r--r-- | kernel/module.c | 76 | ||||
-rw-r--r-- | kernel/params.c | 28 | ||||
-rw-r--r-- | kernel/power/Kconfig | 26 | ||||
-rw-r--r-- | kernel/resource.c | 62 |
7 files changed, 282 insertions, 26 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index fc723e595cd5..d57118da73ff 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1313,7 +1313,7 @@ noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_re | |||
1313 | return regs; | 1313 | return regs; |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | struct task_struct * __devinit fork_idle(int cpu) | 1316 | struct task_struct * __cpuinit fork_idle(int cpu) |
1317 | { | 1317 | { |
1318 | struct task_struct *task; | 1318 | struct task_struct *task; |
1319 | struct pt_regs regs; | 1319 | struct pt_regs regs; |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index d27b25855743..475e8a71bcdc 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -39,6 +39,7 @@ void dynamic_irq_init(unsigned int irq) | |||
39 | desc->chip = &no_irq_chip; | 39 | desc->chip = &no_irq_chip; |
40 | desc->handle_irq = handle_bad_irq; | 40 | desc->handle_irq = handle_bad_irq; |
41 | desc->depth = 1; | 41 | desc->depth = 1; |
42 | desc->msi_desc = NULL; | ||
42 | desc->handler_data = NULL; | 43 | desc->handler_data = NULL; |
43 | desc->chip_data = NULL; | 44 | desc->chip_data = NULL; |
44 | desc->action = NULL; | 45 | desc->action = NULL; |
@@ -74,6 +75,9 @@ void dynamic_irq_cleanup(unsigned int irq) | |||
74 | WARN_ON(1); | 75 | WARN_ON(1); |
75 | return; | 76 | return; |
76 | } | 77 | } |
78 | desc->msi_desc = NULL; | ||
79 | desc->handler_data = NULL; | ||
80 | desc->chip_data = NULL; | ||
77 | desc->handle_irq = handle_bad_irq; | 81 | desc->handle_irq = handle_bad_irq; |
78 | desc->chip = &no_irq_chip; | 82 | desc->chip = &no_irq_chip; |
79 | spin_unlock_irqrestore(&desc->lock, flags); | 83 | spin_unlock_irqrestore(&desc->lock, flags); |
@@ -162,6 +166,30 @@ int set_irq_data(unsigned int irq, void *data) | |||
162 | EXPORT_SYMBOL(set_irq_data); | 166 | EXPORT_SYMBOL(set_irq_data); |
163 | 167 | ||
164 | /** | 168 | /** |
169 | * set_irq_data - set irq type data for an irq | ||
170 | * @irq: Interrupt number | ||
171 | * @data: Pointer to interrupt specific data | ||
172 | * | ||
173 | * Set the hardware irq controller data for an irq | ||
174 | */ | ||
175 | int set_irq_msi(unsigned int irq, struct msi_desc *entry) | ||
176 | { | ||
177 | struct irq_desc *desc; | ||
178 | unsigned long flags; | ||
179 | |||
180 | if (irq >= NR_IRQS) { | ||
181 | printk(KERN_ERR | ||
182 | "Trying to install msi data for IRQ%d\n", irq); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | desc = irq_desc + irq; | ||
186 | spin_lock_irqsave(&desc->lock, flags); | ||
187 | desc->msi_desc = entry; | ||
188 | spin_unlock_irqrestore(&desc->lock, flags); | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | /** | ||
165 | * set_irq_chip_data - set irq chip data for an irq | 193 | * set_irq_chip_data - set irq chip data for an irq |
166 | * @irq: Interrupt number | 194 | * @irq: Interrupt number |
167 | * @data: Pointer to chip specific data | 195 | * @data: Pointer to chip specific data |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 8b961adc3bd2..c4b7ed1cebf7 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -482,3 +482,89 @@ int request_irq(unsigned int irq, irq_handler_t handler, | |||
482 | return retval; | 482 | return retval; |
483 | } | 483 | } |
484 | EXPORT_SYMBOL(request_irq); | 484 | EXPORT_SYMBOL(request_irq); |
485 | |||
486 | /* | ||
487 | * Device resource management aware IRQ request/free implementation. | ||
488 | */ | ||
489 | struct irq_devres { | ||
490 | unsigned int irq; | ||
491 | void *dev_id; | ||
492 | }; | ||
493 | |||
494 | static void devm_irq_release(struct device *dev, void *res) | ||
495 | { | ||
496 | struct irq_devres *this = res; | ||
497 | |||
498 | free_irq(this->irq, this->dev_id); | ||
499 | } | ||
500 | |||
501 | static int devm_irq_match(struct device *dev, void *res, void *data) | ||
502 | { | ||
503 | struct irq_devres *this = res, *match = data; | ||
504 | |||
505 | return this->irq == match->irq && this->dev_id == match->dev_id; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * devm_request_irq - allocate an interrupt line for a managed device | ||
510 | * @dev: device to request interrupt for | ||
511 | * @irq: Interrupt line to allocate | ||
512 | * @handler: Function to be called when the IRQ occurs | ||
513 | * @irqflags: Interrupt type flags | ||
514 | * @devname: An ascii name for the claiming device | ||
515 | * @dev_id: A cookie passed back to the handler function | ||
516 | * | ||
517 | * Except for the extra @dev argument, this function takes the | ||
518 | * same arguments and performs the same function as | ||
519 | * request_irq(). IRQs requested with this function will be | ||
520 | * automatically freed on driver detach. | ||
521 | * | ||
522 | * If an IRQ allocated with this function needs to be freed | ||
523 | * separately, dev_free_irq() must be used. | ||
524 | */ | ||
525 | int devm_request_irq(struct device *dev, unsigned int irq, | ||
526 | irq_handler_t handler, unsigned long irqflags, | ||
527 | const char *devname, void *dev_id) | ||
528 | { | ||
529 | struct irq_devres *dr; | ||
530 | int rc; | ||
531 | |||
532 | dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), | ||
533 | GFP_KERNEL); | ||
534 | if (!dr) | ||
535 | return -ENOMEM; | ||
536 | |||
537 | rc = request_irq(irq, handler, irqflags, devname, dev_id); | ||
538 | if (rc) { | ||
539 | kfree(dr); | ||
540 | return rc; | ||
541 | } | ||
542 | |||
543 | dr->irq = irq; | ||
544 | dr->dev_id = dev_id; | ||
545 | devres_add(dev, dr); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | EXPORT_SYMBOL(devm_request_irq); | ||
550 | |||
551 | /** | ||
552 | * devm_free_irq - free an interrupt | ||
553 | * @dev: device to free interrupt for | ||
554 | * @irq: Interrupt line to free | ||
555 | * @dev_id: Device identity to free | ||
556 | * | ||
557 | * Except for the extra @dev argument, this function takes the | ||
558 | * same arguments and performs the same function as free_irq(). | ||
559 | * This function instead of free_irq() should be used to manually | ||
560 | * free IRQs allocated with dev_request_irq(). | ||
561 | */ | ||
562 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | ||
563 | { | ||
564 | struct irq_devres match_data = { irq, dev_id }; | ||
565 | |||
566 | free_irq(irq, dev_id); | ||
567 | WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, | ||
568 | &match_data)); | ||
569 | } | ||
570 | EXPORT_SYMBOL(devm_free_irq); | ||
diff --git a/kernel/module.c b/kernel/module.c index d0f2260a0210..8a94e054230c 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -537,6 +537,8 @@ static int already_uses(struct module *a, struct module *b) | |||
537 | static int use_module(struct module *a, struct module *b) | 537 | static int use_module(struct module *a, struct module *b) |
538 | { | 538 | { |
539 | struct module_use *use; | 539 | struct module_use *use; |
540 | int no_warn; | ||
541 | |||
540 | if (b == NULL || already_uses(a, b)) return 1; | 542 | if (b == NULL || already_uses(a, b)) return 1; |
541 | 543 | ||
542 | if (!strong_try_module_get(b)) | 544 | if (!strong_try_module_get(b)) |
@@ -552,6 +554,7 @@ static int use_module(struct module *a, struct module *b) | |||
552 | 554 | ||
553 | use->module_which_uses = a; | 555 | use->module_which_uses = a; |
554 | list_add(&use->list, &b->modules_which_use_me); | 556 | list_add(&use->list, &b->modules_which_use_me); |
557 | no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); | ||
555 | return 1; | 558 | return 1; |
556 | } | 559 | } |
557 | 560 | ||
@@ -569,6 +572,7 @@ static void module_unload_free(struct module *mod) | |||
569 | module_put(i); | 572 | module_put(i); |
570 | list_del(&use->list); | 573 | list_del(&use->list); |
571 | kfree(use); | 574 | kfree(use); |
575 | sysfs_remove_link(i->holders_dir, mod->name); | ||
572 | /* There can be at most one match. */ | 576 | /* There can be at most one match. */ |
573 | break; | 577 | break; |
574 | } | 578 | } |
@@ -1106,9 +1110,7 @@ static void module_remove_modinfo_attrs(struct module *mod) | |||
1106 | kfree(mod->modinfo_attrs); | 1110 | kfree(mod->modinfo_attrs); |
1107 | } | 1111 | } |
1108 | 1112 | ||
1109 | static int mod_sysfs_setup(struct module *mod, | 1113 | static int mod_sysfs_init(struct module *mod) |
1110 | struct kernel_param *kparam, | ||
1111 | unsigned int num_params) | ||
1112 | { | 1114 | { |
1113 | int err; | 1115 | int err; |
1114 | 1116 | ||
@@ -1125,21 +1127,30 @@ static int mod_sysfs_setup(struct module *mod, | |||
1125 | kobj_set_kset_s(&mod->mkobj, module_subsys); | 1127 | kobj_set_kset_s(&mod->mkobj, module_subsys); |
1126 | mod->mkobj.mod = mod; | 1128 | mod->mkobj.mod = mod; |
1127 | 1129 | ||
1128 | /* delay uevent until full sysfs population */ | ||
1129 | kobject_init(&mod->mkobj.kobj); | 1130 | kobject_init(&mod->mkobj.kobj); |
1131 | |||
1132 | out: | ||
1133 | return err; | ||
1134 | } | ||
1135 | |||
1136 | static int mod_sysfs_setup(struct module *mod, | ||
1137 | struct kernel_param *kparam, | ||
1138 | unsigned int num_params) | ||
1139 | { | ||
1140 | int err; | ||
1141 | |||
1142 | /* delay uevent until full sysfs population */ | ||
1130 | err = kobject_add(&mod->mkobj.kobj); | 1143 | err = kobject_add(&mod->mkobj.kobj); |
1131 | if (err) | 1144 | if (err) |
1132 | goto out; | 1145 | goto out; |
1133 | 1146 | ||
1134 | mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers"); | 1147 | mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders"); |
1135 | if (!mod->drivers_dir) { | 1148 | if (!mod->holders_dir) |
1136 | err = -ENOMEM; | ||
1137 | goto out_unreg; | 1149 | goto out_unreg; |
1138 | } | ||
1139 | 1150 | ||
1140 | err = module_param_sysfs_setup(mod, kparam, num_params); | 1151 | err = module_param_sysfs_setup(mod, kparam, num_params); |
1141 | if (err) | 1152 | if (err) |
1142 | goto out_unreg_drivers; | 1153 | goto out_unreg_holders; |
1143 | 1154 | ||
1144 | err = module_add_modinfo_attrs(mod); | 1155 | err = module_add_modinfo_attrs(mod); |
1145 | if (err) | 1156 | if (err) |
@@ -1150,8 +1161,8 @@ static int mod_sysfs_setup(struct module *mod, | |||
1150 | 1161 | ||
1151 | out_unreg_param: | 1162 | out_unreg_param: |
1152 | module_param_sysfs_remove(mod); | 1163 | module_param_sysfs_remove(mod); |
1153 | out_unreg_drivers: | 1164 | out_unreg_holders: |
1154 | kobject_unregister(mod->drivers_dir); | 1165 | kobject_unregister(mod->holders_dir); |
1155 | out_unreg: | 1166 | out_unreg: |
1156 | kobject_del(&mod->mkobj.kobj); | 1167 | kobject_del(&mod->mkobj.kobj); |
1157 | kobject_put(&mod->mkobj.kobj); | 1168 | kobject_put(&mod->mkobj.kobj); |
@@ -1163,7 +1174,10 @@ static void mod_kobject_remove(struct module *mod) | |||
1163 | { | 1174 | { |
1164 | module_remove_modinfo_attrs(mod); | 1175 | module_remove_modinfo_attrs(mod); |
1165 | module_param_sysfs_remove(mod); | 1176 | module_param_sysfs_remove(mod); |
1166 | kobject_unregister(mod->drivers_dir); | 1177 | if (mod->mkobj.drivers_dir) |
1178 | kobject_unregister(mod->mkobj.drivers_dir); | ||
1179 | if (mod->holders_dir) | ||
1180 | kobject_unregister(mod->holders_dir); | ||
1167 | 1181 | ||
1168 | kobject_unregister(&mod->mkobj.kobj); | 1182 | kobject_unregister(&mod->mkobj.kobj); |
1169 | } | 1183 | } |
@@ -1768,6 +1782,10 @@ static struct module *load_module(void __user *umod, | |||
1768 | /* Now we've moved module, initialize linked lists, etc. */ | 1782 | /* Now we've moved module, initialize linked lists, etc. */ |
1769 | module_unload_init(mod); | 1783 | module_unload_init(mod); |
1770 | 1784 | ||
1785 | /* Initialize kobject, so we can reference it. */ | ||
1786 | if (mod_sysfs_init(mod) != 0) | ||
1787 | goto cleanup; | ||
1788 | |||
1771 | /* Set up license info based on the info section */ | 1789 | /* Set up license info based on the info section */ |
1772 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); | 1790 | set_license(mod, get_modinfo(sechdrs, infoindex, "license")); |
1773 | 1791 | ||
@@ -2340,19 +2358,43 @@ static char *make_driver_name(struct device_driver *drv) | |||
2340 | return driver_name; | 2358 | return driver_name; |
2341 | } | 2359 | } |
2342 | 2360 | ||
2361 | static void module_create_drivers_dir(struct module_kobject *mk) | ||
2362 | { | ||
2363 | if (!mk || mk->drivers_dir) | ||
2364 | return; | ||
2365 | |||
2366 | mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers"); | ||
2367 | } | ||
2368 | |||
2343 | void module_add_driver(struct module *mod, struct device_driver *drv) | 2369 | void module_add_driver(struct module *mod, struct device_driver *drv) |
2344 | { | 2370 | { |
2345 | char *driver_name; | 2371 | char *driver_name; |
2346 | int no_warn; | 2372 | int no_warn; |
2373 | struct module_kobject *mk = NULL; | ||
2374 | |||
2375 | if (!drv) | ||
2376 | return; | ||
2377 | |||
2378 | if (mod) | ||
2379 | mk = &mod->mkobj; | ||
2380 | else if (drv->mod_name) { | ||
2381 | struct kobject *mkobj; | ||
2382 | |||
2383 | /* Lookup built-in module entry in /sys/modules */ | ||
2384 | mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name); | ||
2385 | if (mkobj) | ||
2386 | mk = container_of(mkobj, struct module_kobject, kobj); | ||
2387 | } | ||
2347 | 2388 | ||
2348 | if (!mod || !drv) | 2389 | if (!mk) |
2349 | return; | 2390 | return; |
2350 | 2391 | ||
2351 | /* Don't check return codes; these calls are idempotent */ | 2392 | /* Don't check return codes; these calls are idempotent */ |
2352 | no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module"); | 2393 | no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); |
2353 | driver_name = make_driver_name(drv); | 2394 | driver_name = make_driver_name(drv); |
2354 | if (driver_name) { | 2395 | if (driver_name) { |
2355 | no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj, | 2396 | module_create_drivers_dir(mk); |
2397 | no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, | ||
2356 | driver_name); | 2398 | driver_name); |
2357 | kfree(driver_name); | 2399 | kfree(driver_name); |
2358 | } | 2400 | } |
@@ -2367,10 +2409,10 @@ void module_remove_driver(struct device_driver *drv) | |||
2367 | return; | 2409 | return; |
2368 | 2410 | ||
2369 | sysfs_remove_link(&drv->kobj, "module"); | 2411 | sysfs_remove_link(&drv->kobj, "module"); |
2370 | if (drv->owner && drv->owner->drivers_dir) { | 2412 | if (drv->owner && drv->owner->mkobj.drivers_dir) { |
2371 | driver_name = make_driver_name(drv); | 2413 | driver_name = make_driver_name(drv); |
2372 | if (driver_name) { | 2414 | if (driver_name) { |
2373 | sysfs_remove_link(drv->owner->drivers_dir, | 2415 | sysfs_remove_link(drv->owner->mkobj.drivers_dir, |
2374 | driver_name); | 2416 | driver_name); |
2375 | kfree(driver_name); | 2417 | kfree(driver_name); |
2376 | } | 2418 | } |
diff --git a/kernel/params.c b/kernel/params.c index 718945da8f58..553cf7d6a4be 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #define DEBUGP(fmt, a...) | 30 | #define DEBUGP(fmt, a...) |
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | static struct kobj_type module_ktype; | ||
34 | |||
33 | static inline char dash2underscore(char c) | 35 | static inline char dash2underscore(char c) |
34 | { | 36 | { |
35 | if (c == '-') | 37 | if (c == '-') |
@@ -561,14 +563,11 @@ static void __init kernel_param_sysfs_setup(const char *name, | |||
561 | mk->mod = THIS_MODULE; | 563 | mk->mod = THIS_MODULE; |
562 | kobj_set_kset_s(mk, module_subsys); | 564 | kobj_set_kset_s(mk, module_subsys); |
563 | kobject_set_name(&mk->kobj, name); | 565 | kobject_set_name(&mk->kobj, name); |
564 | ret = kobject_register(&mk->kobj); | 566 | kobject_init(&mk->kobj); |
567 | ret = kobject_add(&mk->kobj); | ||
565 | BUG_ON(ret < 0); | 568 | BUG_ON(ret < 0); |
566 | 569 | param_sysfs_setup(mk, kparam, num_params, name_skip); | |
567 | /* no need to keep the kobject if no parameter is exported */ | 570 | kobject_uevent(&mk->kobj, KOBJ_ADD); |
568 | if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) { | ||
569 | kobject_unregister(&mk->kobj); | ||
570 | kfree(mk); | ||
571 | } | ||
572 | } | 571 | } |
573 | 572 | ||
574 | /* | 573 | /* |
@@ -674,6 +673,19 @@ static struct sysfs_ops module_sysfs_ops = { | |||
674 | .store = module_attr_store, | 673 | .store = module_attr_store, |
675 | }; | 674 | }; |
676 | 675 | ||
676 | static int uevent_filter(struct kset *kset, struct kobject *kobj) | ||
677 | { | ||
678 | struct kobj_type *ktype = get_ktype(kobj); | ||
679 | |||
680 | if (ktype == &module_ktype) | ||
681 | return 1; | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static struct kset_uevent_ops module_uevent_ops = { | ||
686 | .filter = uevent_filter, | ||
687 | }; | ||
688 | |||
677 | #else | 689 | #else |
678 | static struct sysfs_ops module_sysfs_ops = { | 690 | static struct sysfs_ops module_sysfs_ops = { |
679 | .show = NULL, | 691 | .show = NULL, |
@@ -685,7 +697,7 @@ static struct kobj_type module_ktype = { | |||
685 | .sysfs_ops = &module_sysfs_ops, | 697 | .sysfs_ops = &module_sysfs_ops, |
686 | }; | 698 | }; |
687 | 699 | ||
688 | decl_subsys(module, &module_ktype, NULL); | 700 | decl_subsys(module, &module_ktype, &module_uevent_ops); |
689 | 701 | ||
690 | /* | 702 | /* |
691 | * param_sysfs_init - wrapper for built-in params support | 703 | * param_sysfs_init - wrapper for built-in params support |
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index ed296225dcd4..95f6657fff73 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig | |||
@@ -131,3 +131,29 @@ config SUSPEND_SMP | |||
131 | bool | 131 | bool |
132 | depends on HOTPLUG_CPU && X86 && PM | 132 | depends on HOTPLUG_CPU && X86 && PM |
133 | default y | 133 | default y |
134 | |||
135 | config APM_EMULATION | ||
136 | tristate "Advanced Power Management Emulation" | ||
137 | depends on PM && SYS_SUPPORTS_APM_EMULATION | ||
138 | help | ||
139 | APM is a BIOS specification for saving power using several different | ||
140 | techniques. This is mostly useful for battery powered laptops with | ||
141 | APM compliant BIOSes. If you say Y here, the system time will be | ||
142 | reset after a RESUME operation, the /proc/apm device will provide | ||
143 | battery status information, and user-space programs will receive | ||
144 | notification of APM "events" (e.g. battery status change). | ||
145 | |||
146 | In order to use APM, you will need supporting software. For location | ||
147 | and more information, read <file:Documentation/pm.txt> and the | ||
148 | Battery Powered Linux mini-HOWTO, available from | ||
149 | <http://www.tldp.org/docs.html#howto>. | ||
150 | |||
151 | This driver does not spin down disk drives (see the hdparm(8) | ||
152 | manpage ("man 8 hdparm") for that), and it doesn't turn off | ||
153 | VESA-compliant "green" monitors. | ||
154 | |||
155 | Generally, if you don't have a battery in your machine, there isn't | ||
156 | much point in using this driver and you should say N. If you get | ||
157 | random kernel OOPSes or reboots that don't seem to be related to | ||
158 | anything, try disabling/enabling this option (or disabling/enabling | ||
159 | APM in your BIOS). | ||
diff --git a/kernel/resource.c b/kernel/resource.c index 7b9a497419d9..2a3f88636580 100644 --- a/kernel/resource.c +++ b/kernel/resource.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/proc_fs.h> | 18 | #include <linux/proc_fs.h> |
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/device.h> | ||
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
21 | 22 | ||
22 | 23 | ||
@@ -618,6 +619,67 @@ void __release_region(struct resource *parent, resource_size_t start, | |||
618 | EXPORT_SYMBOL(__release_region); | 619 | EXPORT_SYMBOL(__release_region); |
619 | 620 | ||
620 | /* | 621 | /* |
622 | * Managed region resource | ||
623 | */ | ||
624 | struct region_devres { | ||
625 | struct resource *parent; | ||
626 | resource_size_t start; | ||
627 | resource_size_t n; | ||
628 | }; | ||
629 | |||
630 | static void devm_region_release(struct device *dev, void *res) | ||
631 | { | ||
632 | struct region_devres *this = res; | ||
633 | |||
634 | __release_region(this->parent, this->start, this->n); | ||
635 | } | ||
636 | |||
637 | static int devm_region_match(struct device *dev, void *res, void *match_data) | ||
638 | { | ||
639 | struct region_devres *this = res, *match = match_data; | ||
640 | |||
641 | return this->parent == match->parent && | ||
642 | this->start == match->start && this->n == match->n; | ||
643 | } | ||
644 | |||
645 | struct resource * __devm_request_region(struct device *dev, | ||
646 | struct resource *parent, resource_size_t start, | ||
647 | resource_size_t n, const char *name) | ||
648 | { | ||
649 | struct region_devres *dr = NULL; | ||
650 | struct resource *res; | ||
651 | |||
652 | dr = devres_alloc(devm_region_release, sizeof(struct region_devres), | ||
653 | GFP_KERNEL); | ||
654 | if (!dr) | ||
655 | return NULL; | ||
656 | |||
657 | dr->parent = parent; | ||
658 | dr->start = start; | ||
659 | dr->n = n; | ||
660 | |||
661 | res = __request_region(parent, start, n, name); | ||
662 | if (res) | ||
663 | devres_add(dev, dr); | ||
664 | else | ||
665 | devres_free(dr); | ||
666 | |||
667 | return res; | ||
668 | } | ||
669 | EXPORT_SYMBOL(__devm_request_region); | ||
670 | |||
671 | void __devm_release_region(struct device *dev, struct resource *parent, | ||
672 | resource_size_t start, resource_size_t n) | ||
673 | { | ||
674 | struct region_devres match_data = { parent, start, n }; | ||
675 | |||
676 | __release_region(parent, start, n); | ||
677 | WARN_ON(devres_destroy(dev, devm_region_release, devm_region_match, | ||
678 | &match_data)); | ||
679 | } | ||
680 | EXPORT_SYMBOL(__devm_release_region); | ||
681 | |||
682 | /* | ||
621 | * Called from init/main.c to reserve IO ports. | 683 | * Called from init/main.c to reserve IO ports. |
622 | */ | 684 | */ |
623 | #define MAXRESERVE 4 | 685 | #define MAXRESERVE 4 |