diff options
| -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); | ||
