diff options
author | Al Viro <viro@ftp.linux.org.uk> | 2007-02-11 10:41:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 14:18:07 -0500 |
commit | 5ea8176994003483a18c8fed580901e2125f8a83 (patch) | |
tree | 0712ec9cd3384fbd897eb454ce9c0f907289ab51 | |
parent | 2835fdfa4a7f1400986d76d054237809a9392406 (diff) |
[PATCH] sort the devres mess out
* Split the implementation-agnostic stuff in separate files.
* Make sure that targets using non-default request_irq() pull
kernel/irq/devres.o
* Introduce new symbols (HAS_IOPORT and HAS_IOMEM) defaulting to positive;
allow architectures to turn them off (we needed these symbols anyway for
dependencies of quite a few drivers).
* protect the ioport-related parts of lib/devres.o with CONFIG_HAS_IOPORT.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/arm/Kconfig | 5 | ||||
-rw-r--r-- | arch/cris/Kconfig | 3 | ||||
-rw-r--r-- | arch/h8300/Kconfig | 3 | ||||
-rw-r--r-- | arch/h8300/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/m32r/Kconfig | 3 | ||||
-rw-r--r-- | arch/m68k/Kconfig | 3 | ||||
-rw-r--r-- | arch/m68k/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/m68knommu/Kconfig | 3 | ||||
-rw-r--r-- | arch/s390/Kconfig | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/um/Kconfig | 3 | ||||
-rw-r--r-- | arch/xtensa/Kconfig | 3 | ||||
-rw-r--r-- | include/linux/io.h | 6 | ||||
-rw-r--r-- | include/linux/pci.h | 5 | ||||
-rw-r--r-- | kernel/irq/Makefile | 2 | ||||
-rw-r--r-- | kernel/irq/devres.c | 88 | ||||
-rw-r--r-- | kernel/irq/manage.c | 86 | ||||
-rw-r--r-- | lib/Kconfig | 9 | ||||
-rw-r--r-- | lib/Makefile | 6 | ||||
-rw-r--r-- | lib/devres.c | 300 | ||||
-rw-r--r-- | lib/iomap.c | 296 |
21 files changed, 442 insertions, 397 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index fbf4b2a62b60..5c795193ebba 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -29,6 +29,10 @@ config MMU | |||
29 | bool | 29 | bool |
30 | default y | 30 | default y |
31 | 31 | ||
32 | config NO_IOPORT | ||
33 | bool | ||
34 | default n | ||
35 | |||
32 | config EISA | 36 | config EISA |
33 | bool | 37 | bool |
34 | ---help--- | 38 | ---help--- |
@@ -298,6 +302,7 @@ config ARCH_RPC | |||
298 | select TIMER_ACORN | 302 | select TIMER_ACORN |
299 | select ARCH_MAY_HAVE_PC_FDC | 303 | select ARCH_MAY_HAVE_PC_FDC |
300 | select ISA_DMA_API | 304 | select ISA_DMA_API |
305 | select NO_IOPORT | ||
301 | help | 306 | help |
302 | On the Acorn Risc-PC, Linux can support the internal IDE disk and | 307 | On the Acorn Risc-PC, Linux can support the internal IDE disk and |
303 | CD-ROM interface, serial and parallel port, and the floppy drive. | 308 | CD-ROM interface, serial and parallel port, and the floppy drive. |
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index e3db1427dbe5..4b41248b61ad 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
@@ -44,6 +44,9 @@ config IRQ_PER_CPU | |||
44 | bool | 44 | bool |
45 | default y | 45 | default y |
46 | 46 | ||
47 | config NO_IOPORT | ||
48 | def_bool y | ||
49 | |||
47 | config CRIS | 50 | config CRIS |
48 | bool | 51 | bool |
49 | default y | 52 | default y |
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 146eb28f6225..1734d96422c6 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig | |||
@@ -57,6 +57,9 @@ config TIME_LOW_RES | |||
57 | bool | 57 | bool |
58 | default y | 58 | default y |
59 | 59 | ||
60 | config NO_IOPORT | ||
61 | def_bool y | ||
62 | |||
60 | config ISA | 63 | config ISA |
61 | bool | 64 | bool |
62 | default y | 65 | default y |
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile index 71b6131e98b8..4edbc2ef6ca2 100644 --- a/arch/h8300/kernel/Makefile +++ b/arch/h8300/kernel/Makefile | |||
@@ -6,6 +6,8 @@ extra-y := vmlinux.lds | |||
6 | 6 | ||
7 | obj-y := process.o traps.o ptrace.o ints.o \ | 7 | obj-y := process.o traps.o ptrace.o ints.o \ |
8 | sys_h8300.o time.o semaphore.o signal.o \ | 8 | sys_h8300.o time.o semaphore.o signal.o \ |
9 | setup.o gpio.o init_task.o syscalls.o | 9 | setup.o gpio.o init_task.o syscalls.o devres.o |
10 | |||
11 | devres-y = ../../../kernel/irq/devres.o | ||
10 | 12 | ||
11 | obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o | 13 | obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o |
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 565d0138078e..9740d6b8ae11 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig | |||
@@ -28,6 +28,9 @@ config GENERIC_IRQ_PROBE | |||
28 | bool | 28 | bool |
29 | default y | 29 | default y |
30 | 30 | ||
31 | config NO_IOPORT | ||
32 | def_bool y | ||
33 | |||
31 | source "init/Kconfig" | 34 | source "init/Kconfig" |
32 | 35 | ||
33 | 36 | ||
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 0bffbe6e7e11..a8e1e604dfa8 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig | |||
@@ -42,6 +42,9 @@ config ARCH_MAY_HAVE_PC_FDC | |||
42 | depends on Q40 || (BROKEN && SUN3X) | 42 | depends on Q40 || (BROKEN && SUN3X) |
43 | default y | 43 | default y |
44 | 44 | ||
45 | config NO_IOPORT | ||
46 | def_bool y | ||
47 | |||
45 | mainmenu "Linux/68k Kernel Configuration" | 48 | mainmenu "Linux/68k Kernel Configuration" |
46 | 49 | ||
47 | source "init/Kconfig" | 50 | source "init/Kconfig" |
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile index 1c9ecaa473d5..0b68ab8d63d1 100644 --- a/arch/m68k/kernel/Makefile +++ b/arch/m68k/kernel/Makefile | |||
@@ -10,7 +10,9 @@ endif | |||
10 | extra-y += vmlinux.lds | 10 | extra-y += vmlinux.lds |
11 | 11 | ||
12 | obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ | 12 | obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ |
13 | sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o | 13 | sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o |
14 | |||
15 | devres-y = ../../../kernel/irq/devres.o | ||
14 | 16 | ||
15 | obj-$(CONFIG_PCI) += bios32.o | 17 | obj-$(CONFIG_PCI) += bios32.o |
16 | obj-$(CONFIG_MODULES) += module.o | 18 | obj-$(CONFIG_MODULES) += module.o |
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig index c5fc5406dad0..823f73736bb5 100644 --- a/arch/m68knommu/Kconfig +++ b/arch/m68knommu/Kconfig | |||
@@ -53,6 +53,9 @@ config TIME_LOW_RES | |||
53 | bool | 53 | bool |
54 | default y | 54 | default y |
55 | 55 | ||
56 | config NO_IOPORT | ||
57 | def_bool y | ||
58 | |||
56 | source "init/Kconfig" | 59 | source "init/Kconfig" |
57 | 60 | ||
58 | menu "Processor type and features" | 61 | menu "Processor type and features" |
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index c64973004261..0c83d26ef09a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -41,6 +41,9 @@ config GENERIC_HWEIGHT | |||
41 | config GENERIC_TIME | 41 | config GENERIC_TIME |
42 | def_bool y | 42 | def_bool y |
43 | 43 | ||
44 | config NO_IOPORT | ||
45 | def_bool y | ||
46 | |||
44 | mainmenu "Linux Kernel Configuration" | 47 | mainmenu "Linux Kernel Configuration" |
45 | 48 | ||
46 | config S390 | 49 | config S390 |
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 6616ee05c313..e795f282dece 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile | |||
@@ -12,7 +12,9 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \ | |||
12 | sys_sparc.o sunos_asm.o systbls.o \ | 12 | sys_sparc.o sunos_asm.o systbls.o \ |
13 | time.o windows.o cpu.o devices.o sclow.o \ | 13 | time.o windows.o cpu.o devices.o sclow.o \ |
14 | tadpole.o tick14.o ptrace.o sys_solaris.o \ | 14 | tadpole.o tick14.o ptrace.o sys_solaris.o \ |
15 | unaligned.o muldiv.o semaphore.o prom.o of_device.o | 15 | unaligned.o muldiv.o semaphore.o prom.o of_device.o devres.o |
16 | |||
17 | devres-y = ../../../kernel/irq/devres.o | ||
16 | 18 | ||
17 | obj-$(CONFIG_PCI) += pcic.o | 19 | obj-$(CONFIG_PCI) += pcic.o |
18 | obj-$(CONFIG_SUN4) += sun4setup.o | 20 | obj-$(CONFIG_SUN4) += sun4setup.o |
diff --git a/arch/um/Kconfig b/arch/um/Kconfig index d32a80e6668c..b3a21ba77cd2 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig | |||
@@ -16,6 +16,9 @@ config MMU | |||
16 | bool | 16 | bool |
17 | default y | 17 | default y |
18 | 18 | ||
19 | config NO_IOMEM | ||
20 | def_bool y | ||
21 | |||
19 | mainmenu "Linux/Usermode Kernel Configuration" | 22 | mainmenu "Linux/Usermode Kernel Configuration" |
20 | 23 | ||
21 | config ISA | 24 | config ISA |
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 7c99d518e49e..7fbb44bea37f 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig | |||
@@ -46,6 +46,9 @@ config ARCH_HAS_ILOG2_U64 | |||
46 | bool | 46 | bool |
47 | default n | 47 | default n |
48 | 48 | ||
49 | config NO_IOPORT | ||
50 | def_bool y | ||
51 | |||
49 | source "init/Kconfig" | 52 | source "init/Kconfig" |
50 | 53 | ||
51 | menu "Processor type and features" | 54 | menu "Processor type and features" |
diff --git a/include/linux/io.h b/include/linux/io.h index 9e419ebfc98b..c244a0cc9319 100644 --- a/include/linux/io.h +++ b/include/linux/io.h | |||
@@ -43,12 +43,6 @@ void __iomem * devm_ioremap_nocache(struct device *dev, unsigned long offset, | |||
43 | unsigned long size); | 43 | unsigned long size); |
44 | void devm_iounmap(struct device *dev, void __iomem *addr); | 44 | void devm_iounmap(struct device *dev, void __iomem *addr); |
45 | 45 | ||
46 | void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); | ||
47 | void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); | ||
48 | void __iomem * const * pcim_iomap_table(struct pci_dev *pdev); | ||
49 | |||
50 | int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name); | ||
51 | |||
52 | /** | 46 | /** |
53 | * check_signature - find BIOS signatures | 47 | * check_signature - find BIOS signatures |
54 | * @io_addr: mmio address to check | 48 | * @io_addr: mmio address to check |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 9e3042e7e1cc..98c8765a488e 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -840,6 +840,11 @@ enum pci_fixup_pass { | |||
840 | 840 | ||
841 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); | 841 | void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); |
842 | 842 | ||
843 | void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); | ||
844 | void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); | ||
845 | void __iomem * const * pcim_iomap_table(struct pci_dev *pdev); | ||
846 | int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name); | ||
847 | |||
843 | extern int pci_pci_problems; | 848 | extern int pci_pci_problems; |
844 | #define PCIPCI_FAIL 1 /* No PCI PCI DMA */ | 849 | #define PCIPCI_FAIL 1 /* No PCI PCI DMA */ |
845 | #define PCIPCI_TRITON 2 | 850 | #define PCIPCI_TRITON 2 |
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 1dab0ac3f797..681c52dbfe22 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | 1 | ||
2 | obj-y := handle.o manage.o spurious.o resend.o chip.o | 2 | obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o |
3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | 3 | obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o |
4 | obj-$(CONFIG_PROC_FS) += proc.o | 4 | obj-$(CONFIG_PROC_FS) += proc.o |
5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c new file mode 100644 index 000000000000..85a430da0fb6 --- /dev/null +++ b/kernel/irq/devres.c | |||
@@ -0,0 +1,88 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/interrupt.h> | ||
3 | |||
4 | /* | ||
5 | * Device resource management aware IRQ request/free implementation. | ||
6 | */ | ||
7 | struct irq_devres { | ||
8 | unsigned int irq; | ||
9 | void *dev_id; | ||
10 | }; | ||
11 | |||
12 | static void devm_irq_release(struct device *dev, void *res) | ||
13 | { | ||
14 | struct irq_devres *this = res; | ||
15 | |||
16 | free_irq(this->irq, this->dev_id); | ||
17 | } | ||
18 | |||
19 | static int devm_irq_match(struct device *dev, void *res, void *data) | ||
20 | { | ||
21 | struct irq_devres *this = res, *match = data; | ||
22 | |||
23 | return this->irq == match->irq && this->dev_id == match->dev_id; | ||
24 | } | ||
25 | |||
26 | /** | ||
27 | * devm_request_irq - allocate an interrupt line for a managed device | ||
28 | * @dev: device to request interrupt for | ||
29 | * @irq: Interrupt line to allocate | ||
30 | * @handler: Function to be called when the IRQ occurs | ||
31 | * @irqflags: Interrupt type flags | ||
32 | * @devname: An ascii name for the claiming device | ||
33 | * @dev_id: A cookie passed back to the handler function | ||
34 | * | ||
35 | * Except for the extra @dev argument, this function takes the | ||
36 | * same arguments and performs the same function as | ||
37 | * request_irq(). IRQs requested with this function will be | ||
38 | * automatically freed on driver detach. | ||
39 | * | ||
40 | * If an IRQ allocated with this function needs to be freed | ||
41 | * separately, dev_free_irq() must be used. | ||
42 | */ | ||
43 | int devm_request_irq(struct device *dev, unsigned int irq, | ||
44 | irq_handler_t handler, unsigned long irqflags, | ||
45 | const char *devname, void *dev_id) | ||
46 | { | ||
47 | struct irq_devres *dr; | ||
48 | int rc; | ||
49 | |||
50 | dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), | ||
51 | GFP_KERNEL); | ||
52 | if (!dr) | ||
53 | return -ENOMEM; | ||
54 | |||
55 | rc = request_irq(irq, handler, irqflags, devname, dev_id); | ||
56 | if (rc) { | ||
57 | kfree(dr); | ||
58 | return rc; | ||
59 | } | ||
60 | |||
61 | dr->irq = irq; | ||
62 | dr->dev_id = dev_id; | ||
63 | devres_add(dev, dr); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | EXPORT_SYMBOL(devm_request_irq); | ||
68 | |||
69 | /** | ||
70 | * devm_free_irq - free an interrupt | ||
71 | * @dev: device to free interrupt for | ||
72 | * @irq: Interrupt line to free | ||
73 | * @dev_id: Device identity to free | ||
74 | * | ||
75 | * Except for the extra @dev argument, this function takes the | ||
76 | * same arguments and performs the same function as free_irq(). | ||
77 | * This function instead of free_irq() should be used to manually | ||
78 | * free IRQs allocated with dev_request_irq(). | ||
79 | */ | ||
80 | void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) | ||
81 | { | ||
82 | struct irq_devres match_data = { irq, dev_id }; | ||
83 | |||
84 | free_irq(irq, dev_id); | ||
85 | WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, | ||
86 | &match_data)); | ||
87 | } | ||
88 | EXPORT_SYMBOL(devm_free_irq); | ||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index c4b7ed1cebf7..8b961adc3bd2 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -482,89 +482,3 @@ 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/lib/Kconfig b/lib/Kconfig index 9b03581cdecb..384249915047 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
@@ -101,9 +101,14 @@ config TEXTSEARCH_FSM | |||
101 | config PLIST | 101 | config PLIST |
102 | boolean | 102 | boolean |
103 | 103 | ||
104 | config IOMAP_COPY | 104 | config HAS_IOMEM |
105 | boolean | 105 | boolean |
106 | depends on !UML | 106 | depends on !NO_IOMEM |
107 | default y | ||
108 | |||
109 | config HAS_IOPORT | ||
110 | boolean | ||
111 | depends on HAS_IOMEM && !NO_IOPORT | ||
107 | default y | 112 | default y |
108 | 113 | ||
109 | endmenu | 114 | endmenu |
diff --git a/lib/Makefile b/lib/Makefile index b819e37440db..992a39ef9ffd 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -12,15 +12,15 @@ lib-$(CONFIG_SMP) += cpumask.o | |||
12 | 12 | ||
13 | lib-y += kobject.o kref.o kobject_uevent.o klist.o | 13 | lib-y += kobject.o kref.o kobject_uevent.o klist.o |
14 | 14 | ||
15 | obj-y += sort.o parser.o halfmd4.o debug_locks.o random32.o iomap.o \ | 15 | obj-y += sort.o parser.o halfmd4.o debug_locks.o random32.o bust_spinlocks.o |
16 | bust_spinlocks.o | ||
17 | 16 | ||
18 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) | 17 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) |
19 | CFLAGS_kobject.o += -DDEBUG | 18 | CFLAGS_kobject.o += -DDEBUG |
20 | CFLAGS_kobject_uevent.o += -DDEBUG | 19 | CFLAGS_kobject_uevent.o += -DDEBUG |
21 | endif | 20 | endif |
22 | 21 | ||
23 | obj-$(CONFIG_IOMAP_COPY) += iomap_copy.o | 22 | obj-$(CONFIG_GENERIC_IOMAP) += iomap.o |
23 | obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o | ||
24 | obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o | 24 | obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o |
25 | obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o | 25 | obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o |
26 | lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o | 26 | lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o |
diff --git a/lib/devres.c b/lib/devres.c new file mode 100644 index 000000000000..2a668dd7cac7 --- /dev/null +++ b/lib/devres.c | |||
@@ -0,0 +1,300 @@ | |||
1 | #include <linux/pci.h> | ||
2 | #include <linux/io.h> | ||
3 | #include <linux/module.h> | ||
4 | |||
5 | static void devm_ioremap_release(struct device *dev, void *res) | ||
6 | { | ||
7 | iounmap(*(void __iomem **)res); | ||
8 | } | ||
9 | |||
10 | static int devm_ioremap_match(struct device *dev, void *res, void *match_data) | ||
11 | { | ||
12 | return *(void **)res == match_data; | ||
13 | } | ||
14 | |||
15 | /** | ||
16 | * devm_ioremap - Managed ioremap() | ||
17 | * @dev: Generic device to remap IO address for | ||
18 | * @offset: BUS offset to map | ||
19 | * @size: Size of map | ||
20 | * | ||
21 | * Managed ioremap(). Map is automatically unmapped on driver detach. | ||
22 | */ | ||
23 | void __iomem *devm_ioremap(struct device *dev, unsigned long offset, | ||
24 | unsigned long size) | ||
25 | { | ||
26 | void __iomem **ptr, *addr; | ||
27 | |||
28 | ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); | ||
29 | if (!ptr) | ||
30 | return NULL; | ||
31 | |||
32 | addr = ioremap(offset, size); | ||
33 | if (addr) { | ||
34 | *ptr = addr; | ||
35 | devres_add(dev, ptr); | ||
36 | } else | ||
37 | devres_free(ptr); | ||
38 | |||
39 | return addr; | ||
40 | } | ||
41 | EXPORT_SYMBOL(devm_ioremap); | ||
42 | |||
43 | /** | ||
44 | * devm_ioremap_nocache - Managed ioremap_nocache() | ||
45 | * @dev: Generic device to remap IO address for | ||
46 | * @offset: BUS offset to map | ||
47 | * @size: Size of map | ||
48 | * | ||
49 | * Managed ioremap_nocache(). Map is automatically unmapped on driver | ||
50 | * detach. | ||
51 | */ | ||
52 | void __iomem *devm_ioremap_nocache(struct device *dev, unsigned long offset, | ||
53 | unsigned long size) | ||
54 | { | ||
55 | void __iomem **ptr, *addr; | ||
56 | |||
57 | ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); | ||
58 | if (!ptr) | ||
59 | return NULL; | ||
60 | |||
61 | addr = ioremap_nocache(offset, size); | ||
62 | if (addr) { | ||
63 | *ptr = addr; | ||
64 | devres_add(dev, ptr); | ||
65 | } else | ||
66 | devres_free(ptr); | ||
67 | |||
68 | return addr; | ||
69 | } | ||
70 | EXPORT_SYMBOL(devm_ioremap_nocache); | ||
71 | |||
72 | /** | ||
73 | * devm_iounmap - Managed iounmap() | ||
74 | * @dev: Generic device to unmap for | ||
75 | * @addr: Address to unmap | ||
76 | * | ||
77 | * Managed iounmap(). @addr must have been mapped using devm_ioremap*(). | ||
78 | */ | ||
79 | void devm_iounmap(struct device *dev, void __iomem *addr) | ||
80 | { | ||
81 | iounmap(addr); | ||
82 | WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match, | ||
83 | (void *)addr)); | ||
84 | } | ||
85 | EXPORT_SYMBOL(devm_iounmap); | ||
86 | |||
87 | #ifdef CONFIG_HAS_IOPORT | ||
88 | /* | ||
89 | * Generic iomap devres | ||
90 | */ | ||
91 | static void devm_ioport_map_release(struct device *dev, void *res) | ||
92 | { | ||
93 | ioport_unmap(*(void __iomem **)res); | ||
94 | } | ||
95 | |||
96 | static int devm_ioport_map_match(struct device *dev, void *res, | ||
97 | void *match_data) | ||
98 | { | ||
99 | return *(void **)res == match_data; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * devm_ioport_map - Managed ioport_map() | ||
104 | * @dev: Generic device to map ioport for | ||
105 | * @port: Port to map | ||
106 | * @nr: Number of ports to map | ||
107 | * | ||
108 | * Managed ioport_map(). Map is automatically unmapped on driver | ||
109 | * detach. | ||
110 | */ | ||
111 | void __iomem * devm_ioport_map(struct device *dev, unsigned long port, | ||
112 | unsigned int nr) | ||
113 | { | ||
114 | void __iomem **ptr, *addr; | ||
115 | |||
116 | ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL); | ||
117 | if (!ptr) | ||
118 | return NULL; | ||
119 | |||
120 | addr = ioport_map(port, nr); | ||
121 | if (addr) { | ||
122 | *ptr = addr; | ||
123 | devres_add(dev, ptr); | ||
124 | } else | ||
125 | devres_free(ptr); | ||
126 | |||
127 | return addr; | ||
128 | } | ||
129 | EXPORT_SYMBOL(devm_ioport_map); | ||
130 | |||
131 | /** | ||
132 | * devm_ioport_unmap - Managed ioport_unmap() | ||
133 | * @dev: Generic device to unmap for | ||
134 | * @addr: Address to unmap | ||
135 | * | ||
136 | * Managed ioport_unmap(). @addr must have been mapped using | ||
137 | * devm_ioport_map(). | ||
138 | */ | ||
139 | void devm_ioport_unmap(struct device *dev, void __iomem *addr) | ||
140 | { | ||
141 | ioport_unmap(addr); | ||
142 | WARN_ON(devres_destroy(dev, devm_ioport_map_release, | ||
143 | devm_ioport_map_match, (void *)addr)); | ||
144 | } | ||
145 | EXPORT_SYMBOL(devm_ioport_unmap); | ||
146 | |||
147 | #ifdef CONFIG_PCI | ||
148 | /* | ||
149 | * PCI iomap devres | ||
150 | */ | ||
151 | #define PCIM_IOMAP_MAX PCI_ROM_RESOURCE | ||
152 | |||
153 | struct pcim_iomap_devres { | ||
154 | void __iomem *table[PCIM_IOMAP_MAX]; | ||
155 | }; | ||
156 | |||
157 | static void pcim_iomap_release(struct device *gendev, void *res) | ||
158 | { | ||
159 | struct pci_dev *dev = container_of(gendev, struct pci_dev, dev); | ||
160 | struct pcim_iomap_devres *this = res; | ||
161 | int i; | ||
162 | |||
163 | for (i = 0; i < PCIM_IOMAP_MAX; i++) | ||
164 | if (this->table[i]) | ||
165 | pci_iounmap(dev, this->table[i]); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * pcim_iomap_table - access iomap allocation table | ||
170 | * @pdev: PCI device to access iomap table for | ||
171 | * | ||
172 | * Access iomap allocation table for @dev. If iomap table doesn't | ||
173 | * exist and @pdev is managed, it will be allocated. All iomaps | ||
174 | * recorded in the iomap table are automatically unmapped on driver | ||
175 | * detach. | ||
176 | * | ||
177 | * This function might sleep when the table is first allocated but can | ||
178 | * be safely called without context and guaranteed to succed once | ||
179 | * allocated. | ||
180 | */ | ||
181 | void __iomem * const * pcim_iomap_table(struct pci_dev *pdev) | ||
182 | { | ||
183 | struct pcim_iomap_devres *dr, *new_dr; | ||
184 | |||
185 | dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL); | ||
186 | if (dr) | ||
187 | return dr->table; | ||
188 | |||
189 | new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL); | ||
190 | if (!new_dr) | ||
191 | return NULL; | ||
192 | dr = devres_get(&pdev->dev, new_dr, NULL, NULL); | ||
193 | return dr->table; | ||
194 | } | ||
195 | EXPORT_SYMBOL(pcim_iomap_table); | ||
196 | |||
197 | /** | ||
198 | * pcim_iomap - Managed pcim_iomap() | ||
199 | * @pdev: PCI device to iomap for | ||
200 | * @bar: BAR to iomap | ||
201 | * @maxlen: Maximum length of iomap | ||
202 | * | ||
203 | * Managed pci_iomap(). Map is automatically unmapped on driver | ||
204 | * detach. | ||
205 | */ | ||
206 | void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) | ||
207 | { | ||
208 | void __iomem **tbl; | ||
209 | |||
210 | BUG_ON(bar >= PCIM_IOMAP_MAX); | ||
211 | |||
212 | tbl = (void __iomem **)pcim_iomap_table(pdev); | ||
213 | if (!tbl || tbl[bar]) /* duplicate mappings not allowed */ | ||
214 | return NULL; | ||
215 | |||
216 | tbl[bar] = pci_iomap(pdev, bar, maxlen); | ||
217 | return tbl[bar]; | ||
218 | } | ||
219 | EXPORT_SYMBOL(pcim_iomap); | ||
220 | |||
221 | /** | ||
222 | * pcim_iounmap - Managed pci_iounmap() | ||
223 | * @pdev: PCI device to iounmap for | ||
224 | * @addr: Address to unmap | ||
225 | * | ||
226 | * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap(). | ||
227 | */ | ||
228 | void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr) | ||
229 | { | ||
230 | void __iomem **tbl; | ||
231 | int i; | ||
232 | |||
233 | pci_iounmap(pdev, addr); | ||
234 | |||
235 | tbl = (void __iomem **)pcim_iomap_table(pdev); | ||
236 | BUG_ON(!tbl); | ||
237 | |||
238 | for (i = 0; i < PCIM_IOMAP_MAX; i++) | ||
239 | if (tbl[i] == addr) { | ||
240 | tbl[i] = NULL; | ||
241 | return; | ||
242 | } | ||
243 | WARN_ON(1); | ||
244 | } | ||
245 | EXPORT_SYMBOL(pcim_iounmap); | ||
246 | |||
247 | /** | ||
248 | * pcim_iomap_regions - Request and iomap PCI BARs | ||
249 | * @pdev: PCI device to map IO resources for | ||
250 | * @mask: Mask of BARs to request and iomap | ||
251 | * @name: Name used when requesting regions | ||
252 | * | ||
253 | * Request and iomap regions specified by @mask. | ||
254 | */ | ||
255 | int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name) | ||
256 | { | ||
257 | void __iomem * const *iomap; | ||
258 | int i, rc; | ||
259 | |||
260 | iomap = pcim_iomap_table(pdev); | ||
261 | if (!iomap) | ||
262 | return -ENOMEM; | ||
263 | |||
264 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
265 | unsigned long len; | ||
266 | |||
267 | if (!(mask & (1 << i))) | ||
268 | continue; | ||
269 | |||
270 | rc = -EINVAL; | ||
271 | len = pci_resource_len(pdev, i); | ||
272 | if (!len) | ||
273 | goto err_inval; | ||
274 | |||
275 | rc = pci_request_region(pdev, i, name); | ||
276 | if (rc) | ||
277 | goto err_region; | ||
278 | |||
279 | rc = -ENOMEM; | ||
280 | if (!pcim_iomap(pdev, i, 0)) | ||
281 | goto err_iomap; | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | |||
286 | err_iomap: | ||
287 | pcim_iounmap(pdev, iomap[i]); | ||
288 | err_region: | ||
289 | pci_release_region(pdev, i); | ||
290 | err_inval: | ||
291 | while (--i >= 0) { | ||
292 | pcim_iounmap(pdev, iomap[i]); | ||
293 | pci_release_region(pdev, i); | ||
294 | } | ||
295 | |||
296 | return rc; | ||
297 | } | ||
298 | EXPORT_SYMBOL(pcim_iomap_regions); | ||
299 | #endif | ||
300 | #endif | ||
diff --git a/lib/iomap.c b/lib/iomap.c index 4990c736bc4b..4d43f37c0154 100644 --- a/lib/iomap.c +++ b/lib/iomap.c | |||
@@ -6,7 +6,6 @@ | |||
6 | #include <linux/pci.h> | 6 | #include <linux/pci.h> |
7 | #include <linux/io.h> | 7 | #include <linux/io.h> |
8 | 8 | ||
9 | #ifdef CONFIG_GENERIC_IOMAP | ||
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
11 | 10 | ||
12 | /* | 11 | /* |
@@ -256,298 +255,3 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr) | |||
256 | } | 255 | } |
257 | EXPORT_SYMBOL(pci_iomap); | 256 | EXPORT_SYMBOL(pci_iomap); |
258 | EXPORT_SYMBOL(pci_iounmap); | 257 | EXPORT_SYMBOL(pci_iounmap); |
259 | |||
260 | #endif /* CONFIG_GENERIC_IOMAP */ | ||
261 | |||
262 | /* | ||
263 | * Generic iomap devres | ||
264 | */ | ||
265 | static void devm_ioport_map_release(struct device *dev, void *res) | ||
266 | { | ||
267 | ioport_unmap(*(void __iomem **)res); | ||
268 | } | ||
269 | |||
270 | static int devm_ioport_map_match(struct device *dev, void *res, | ||
271 | void *match_data) | ||
272 | { | ||
273 | return *(void **)res == match_data; | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * devm_ioport_map - Managed ioport_map() | ||
278 | * @dev: Generic device to map ioport for | ||
279 | * @port: Port to map | ||
280 | * @nr: Number of ports to map | ||
281 | * | ||
282 | * Managed ioport_map(). Map is automatically unmapped on driver | ||
283 | * detach. | ||
284 | */ | ||
285 | void __iomem * devm_ioport_map(struct device *dev, unsigned long port, | ||
286 | unsigned int nr) | ||
287 | { | ||
288 | void __iomem **ptr, *addr; | ||
289 | |||
290 | ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL); | ||
291 | if (!ptr) | ||
292 | return NULL; | ||
293 | |||
294 | addr = ioport_map(port, nr); | ||
295 | if (addr) { | ||
296 | *ptr = addr; | ||
297 | devres_add(dev, ptr); | ||
298 | } else | ||
299 | devres_free(ptr); | ||
300 | |||
301 | return addr; | ||
302 | } | ||
303 | EXPORT_SYMBOL(devm_ioport_map); | ||
304 | |||
305 | /** | ||
306 | * devm_ioport_unmap - Managed ioport_unmap() | ||
307 | * @dev: Generic device to unmap for | ||
308 | * @addr: Address to unmap | ||
309 | * | ||
310 | * Managed ioport_unmap(). @addr must have been mapped using | ||
311 | * devm_ioport_map(). | ||
312 | */ | ||
313 | void devm_ioport_unmap(struct device *dev, void __iomem *addr) | ||
314 | { | ||
315 | ioport_unmap(addr); | ||
316 | WARN_ON(devres_destroy(dev, devm_ioport_map_release, | ||
317 | devm_ioport_map_match, (void *)addr)); | ||
318 | } | ||
319 | EXPORT_SYMBOL(devm_ioport_unmap); | ||
320 | |||
321 | static void devm_ioremap_release(struct device *dev, void *res) | ||
322 | { | ||
323 | iounmap(*(void __iomem **)res); | ||
324 | } | ||
325 | |||
326 | static int devm_ioremap_match(struct device *dev, void *res, void *match_data) | ||
327 | { | ||
328 | return *(void **)res == match_data; | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * devm_ioremap - Managed ioremap() | ||
333 | * @dev: Generic device to remap IO address for | ||
334 | * @offset: BUS offset to map | ||
335 | * @size: Size of map | ||
336 | * | ||
337 | * Managed ioremap(). Map is automatically unmapped on driver detach. | ||
338 | */ | ||
339 | void __iomem *devm_ioremap(struct device *dev, unsigned long offset, | ||
340 | unsigned long size) | ||
341 | { | ||
342 | void __iomem **ptr, *addr; | ||
343 | |||
344 | ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); | ||
345 | if (!ptr) | ||
346 | return NULL; | ||
347 | |||
348 | addr = ioremap(offset, size); | ||
349 | if (addr) { | ||
350 | *ptr = addr; | ||
351 | devres_add(dev, ptr); | ||
352 | } else | ||
353 | devres_free(ptr); | ||
354 | |||
355 | return addr; | ||
356 | } | ||
357 | EXPORT_SYMBOL(devm_ioremap); | ||
358 | |||
359 | /** | ||
360 | * devm_ioremap_nocache - Managed ioremap_nocache() | ||
361 | * @dev: Generic device to remap IO address for | ||
362 | * @offset: BUS offset to map | ||
363 | * @size: Size of map | ||
364 | * | ||
365 | * Managed ioremap_nocache(). Map is automatically unmapped on driver | ||
366 | * detach. | ||
367 | */ | ||
368 | void __iomem *devm_ioremap_nocache(struct device *dev, unsigned long offset, | ||
369 | unsigned long size) | ||
370 | { | ||
371 | void __iomem **ptr, *addr; | ||
372 | |||
373 | ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); | ||
374 | if (!ptr) | ||
375 | return NULL; | ||
376 | |||
377 | addr = ioremap_nocache(offset, size); | ||
378 | if (addr) { | ||
379 | *ptr = addr; | ||
380 | devres_add(dev, ptr); | ||
381 | } else | ||
382 | devres_free(ptr); | ||
383 | |||
384 | return addr; | ||
385 | } | ||
386 | EXPORT_SYMBOL(devm_ioremap_nocache); | ||
387 | |||
388 | /** | ||
389 | * devm_iounmap - Managed iounmap() | ||
390 | * @dev: Generic device to unmap for | ||
391 | * @addr: Address to unmap | ||
392 | * | ||
393 | * Managed iounmap(). @addr must have been mapped using devm_ioremap*(). | ||
394 | */ | ||
395 | void devm_iounmap(struct device *dev, void __iomem *addr) | ||
396 | { | ||
397 | iounmap(addr); | ||
398 | WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match, | ||
399 | (void *)addr)); | ||
400 | } | ||
401 | EXPORT_SYMBOL(devm_iounmap); | ||
402 | |||
403 | /* | ||
404 | * PCI iomap devres | ||
405 | */ | ||
406 | #define PCIM_IOMAP_MAX PCI_ROM_RESOURCE | ||
407 | |||
408 | struct pcim_iomap_devres { | ||
409 | void __iomem *table[PCIM_IOMAP_MAX]; | ||
410 | }; | ||
411 | |||
412 | static void pcim_iomap_release(struct device *gendev, void *res) | ||
413 | { | ||
414 | struct pci_dev *dev = container_of(gendev, struct pci_dev, dev); | ||
415 | struct pcim_iomap_devres *this = res; | ||
416 | int i; | ||
417 | |||
418 | for (i = 0; i < PCIM_IOMAP_MAX; i++) | ||
419 | if (this->table[i]) | ||
420 | pci_iounmap(dev, this->table[i]); | ||
421 | } | ||
422 | |||
423 | /** | ||
424 | * pcim_iomap_table - access iomap allocation table | ||
425 | * @pdev: PCI device to access iomap table for | ||
426 | * | ||
427 | * Access iomap allocation table for @dev. If iomap table doesn't | ||
428 | * exist and @pdev is managed, it will be allocated. All iomaps | ||
429 | * recorded in the iomap table are automatically unmapped on driver | ||
430 | * detach. | ||
431 | * | ||
432 | * This function might sleep when the table is first allocated but can | ||
433 | * be safely called without context and guaranteed to succed once | ||
434 | * allocated. | ||
435 | */ | ||
436 | void __iomem * const * pcim_iomap_table(struct pci_dev *pdev) | ||
437 | { | ||
438 | struct pcim_iomap_devres *dr, *new_dr; | ||
439 | |||
440 | dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL); | ||
441 | if (dr) | ||
442 | return dr->table; | ||
443 | |||
444 | new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL); | ||
445 | if (!new_dr) | ||
446 | return NULL; | ||
447 | dr = devres_get(&pdev->dev, new_dr, NULL, NULL); | ||
448 | return dr->table; | ||
449 | } | ||
450 | EXPORT_SYMBOL(pcim_iomap_table); | ||
451 | |||
452 | /** | ||
453 | * pcim_iomap - Managed pcim_iomap() | ||
454 | * @pdev: PCI device to iomap for | ||
455 | * @bar: BAR to iomap | ||
456 | * @maxlen: Maximum length of iomap | ||
457 | * | ||
458 | * Managed pci_iomap(). Map is automatically unmapped on driver | ||
459 | * detach. | ||
460 | */ | ||
461 | void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) | ||
462 | { | ||
463 | void __iomem **tbl; | ||
464 | |||
465 | BUG_ON(bar >= PCIM_IOMAP_MAX); | ||
466 | |||
467 | tbl = (void __iomem **)pcim_iomap_table(pdev); | ||
468 | if (!tbl || tbl[bar]) /* duplicate mappings not allowed */ | ||
469 | return NULL; | ||
470 | |||
471 | tbl[bar] = pci_iomap(pdev, bar, maxlen); | ||
472 | return tbl[bar]; | ||
473 | } | ||
474 | EXPORT_SYMBOL(pcim_iomap); | ||
475 | |||
476 | /** | ||
477 | * pcim_iounmap - Managed pci_iounmap() | ||
478 | * @pdev: PCI device to iounmap for | ||
479 | * @addr: Address to unmap | ||
480 | * | ||
481 | * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap(). | ||
482 | */ | ||
483 | void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr) | ||
484 | { | ||
485 | void __iomem **tbl; | ||
486 | int i; | ||
487 | |||
488 | pci_iounmap(pdev, addr); | ||
489 | |||
490 | tbl = (void __iomem **)pcim_iomap_table(pdev); | ||
491 | BUG_ON(!tbl); | ||
492 | |||
493 | for (i = 0; i < PCIM_IOMAP_MAX; i++) | ||
494 | if (tbl[i] == addr) { | ||
495 | tbl[i] = NULL; | ||
496 | return; | ||
497 | } | ||
498 | WARN_ON(1); | ||
499 | } | ||
500 | EXPORT_SYMBOL(pcim_iounmap); | ||
501 | |||
502 | /** | ||
503 | * pcim_iomap_regions - Request and iomap PCI BARs | ||
504 | * @pdev: PCI device to map IO resources for | ||
505 | * @mask: Mask of BARs to request and iomap | ||
506 | * @name: Name used when requesting regions | ||
507 | * | ||
508 | * Request and iomap regions specified by @mask. | ||
509 | */ | ||
510 | int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name) | ||
511 | { | ||
512 | void __iomem * const *iomap; | ||
513 | int i, rc; | ||
514 | |||
515 | iomap = pcim_iomap_table(pdev); | ||
516 | if (!iomap) | ||
517 | return -ENOMEM; | ||
518 | |||
519 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
520 | unsigned long len; | ||
521 | |||
522 | if (!(mask & (1 << i))) | ||
523 | continue; | ||
524 | |||
525 | rc = -EINVAL; | ||
526 | len = pci_resource_len(pdev, i); | ||
527 | if (!len) | ||
528 | goto err_inval; | ||
529 | |||
530 | rc = pci_request_region(pdev, i, name); | ||
531 | if (rc) | ||
532 | goto err_region; | ||
533 | |||
534 | rc = -ENOMEM; | ||
535 | if (!pcim_iomap(pdev, i, 0)) | ||
536 | goto err_iomap; | ||
537 | } | ||
538 | |||
539 | return 0; | ||
540 | |||
541 | err_iomap: | ||
542 | pcim_iounmap(pdev, iomap[i]); | ||
543 | err_region: | ||
544 | pci_release_region(pdev, i); | ||
545 | err_inval: | ||
546 | while (--i >= 0) { | ||
547 | pcim_iounmap(pdev, iomap[i]); | ||
548 | pci_release_region(pdev, i); | ||
549 | } | ||
550 | |||
551 | return rc; | ||
552 | } | ||
553 | EXPORT_SYMBOL(pcim_iomap_regions); | ||