aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-01-20 02:00:26 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-09 17:39:36 -0500
commit9ac7849e35f705830f7b016ff272b0ff1f7ff759 (patch)
tree7f17cdff87e154937a15cc2ec8da9b4e6018ce8e /kernel
parent77a527eadb425b60db3f5f0aae6a4c51c38e35e5 (diff)
devres: device resource management
Implement device resource management, in short, devres. A device driver can allocate arbirary size of devres data which is associated with a release function. On driver detach, release function is invoked on the devres data, then, devres data is freed. devreses are typed by associated release functions. Some devreses are better represented by single instance of the type while others need multiple instances sharing the same release function. Both usages are supported. devreses can be grouped using devres group such that a device driver can easily release acquired resources halfway through initialization or selectively release resources (e.g. resources for port 1 out of 4 ports). This patch adds devres core including documentation and the following managed interfaces. * alloc/free : devm_kzalloc(), devm_kzfree() * IO region : devm_request_region(), devm_release_region() * IRQ : devm_request_irq(), devm_free_irq() * DMA : dmam_alloc_coherent(), dmam_free_coherent(), dmam_declare_coherent_memory(), dmam_pool_create(), dmam_pool_destroy() * PCI : pcim_enable_device(), pcim_pin_device(), pci_is_managed() * iomap : devm_ioport_map(), devm_ioport_unmap(), devm_ioremap(), devm_ioremap_nocache(), devm_iounmap(), pcim_iomap_table(), pcim_iomap(), pcim_iounmap() Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/irq/manage.c86
-rw-r--r--kernel/resource.c62
2 files changed, 148 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8b961adc3bd..c4b7ed1cebf 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}
484EXPORT_SYMBOL(request_irq); 484EXPORT_SYMBOL(request_irq);
485
486/*
487 * Device resource management aware IRQ request/free implementation.
488 */
489struct irq_devres {
490 unsigned int irq;
491 void *dev_id;
492};
493
494static 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
501static 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 */
525int 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}
549EXPORT_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 */
562void 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}
570EXPORT_SYMBOL(devm_free_irq);
diff --git a/kernel/resource.c b/kernel/resource.c
index 7b9a497419d..2a3f8863658 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,
618EXPORT_SYMBOL(__release_region); 619EXPORT_SYMBOL(__release_region);
619 620
620/* 621/*
622 * Managed region resource
623 */
624struct region_devres {
625 struct resource *parent;
626 resource_size_t start;
627 resource_size_t n;
628};
629
630static 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
637static 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
645struct 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}
669EXPORT_SYMBOL(__devm_request_region);
670
671void __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}
680EXPORT_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