diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-20 12:09:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-20 12:09:46 -0400 |
commit | 54291263519ac2c9bdda68b23b02fef3808deed4 (patch) | |
tree | d71de8172a6ab2bbe3068aece7d8911eeeb276fd /drivers/pcmcia/rsrc_nonstatic.c | |
parent | 46ee9645094ad1eb5b4888882ecaa1fb87dcd2a3 (diff) | |
parent | acd200bf45487271d54f05938ad9e30f32a530ee (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6: (29 commits)
pcmcia: disable PCMCIA ioctl also for ARM
drivers/staging/comedi: dev_node removal (quatech_daqp_cs)
drivers/staging/comedi: dev_node removal (ni_mio_cs)
drivers/staging/comedi: dev_node removal (ni_labpc_cs)
drivers/staging/comedi: dev_node removal (ni_daq_dio24)
drivers/staging/comedi: dev_node removal (ni_daq_700)
drivers/staging/comedi: dev_node removal (das08_cs)
drivers/staging/comedi: dev_node removal (cb_das16_cs)
pata_pcmcia: get rid of extra indirection
pcmcia: remove suspend-related comment from yenta_socket.c
pcmcia: call pcmcia_{read,write}_cis_mem with ops_mutex held
pcmcia: remove pcmcia_add_device_lock
pcmcia: update gfp/slab.h includes
pcmcia: remove unused mem_op.h
pcmcia: do not autoadd root PCI bus resources
pcmcia: clarify alloc_io_space, move it to resource handlers
pcmcia: move all pcmcia_resource_ops providers into one module
pcmcia: move high level CIS access code to separate file
pcmcia: dev_node removal (core)
pcmcia: dev_node removal (remaining drivers)
...
Diffstat (limited to 'drivers/pcmcia/rsrc_nonstatic.c')
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 164 |
1 files changed, 130 insertions, 34 deletions
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index a6eb7b59ba9f..dcd1a4ad3d63 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -34,8 +34,10 @@ | |||
34 | #include <pcmcia/cistpl.h> | 34 | #include <pcmcia/cistpl.h> |
35 | #include "cs_internal.h" | 35 | #include "cs_internal.h" |
36 | 36 | ||
37 | /* moved to rsrc_mgr.c | ||
37 | MODULE_AUTHOR("David A. Hinds, Dominik Brodowski"); | 38 | MODULE_AUTHOR("David A. Hinds, Dominik Brodowski"); |
38 | MODULE_LICENSE("GPL"); | 39 | MODULE_LICENSE("GPL"); |
40 | */ | ||
39 | 41 | ||
40 | /* Parameters that can be set with 'insmod' */ | 42 | /* Parameters that can be set with 'insmod' */ |
41 | 43 | ||
@@ -70,27 +72,13 @@ struct socket_data { | |||
70 | ======================================================================*/ | 72 | ======================================================================*/ |
71 | 73 | ||
72 | static struct resource * | 74 | static struct resource * |
73 | make_resource(resource_size_t b, resource_size_t n, int flags, const char *name) | ||
74 | { | ||
75 | struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
76 | |||
77 | if (res) { | ||
78 | res->name = name; | ||
79 | res->start = b; | ||
80 | res->end = b + n - 1; | ||
81 | res->flags = flags; | ||
82 | } | ||
83 | return res; | ||
84 | } | ||
85 | |||
86 | static struct resource * | ||
87 | claim_region(struct pcmcia_socket *s, resource_size_t base, | 75 | claim_region(struct pcmcia_socket *s, resource_size_t base, |
88 | resource_size_t size, int type, char *name) | 76 | resource_size_t size, int type, char *name) |
89 | { | 77 | { |
90 | struct resource *res, *parent; | 78 | struct resource *res, *parent; |
91 | 79 | ||
92 | parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource; | 80 | parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource; |
93 | res = make_resource(base, size, type | IORESOURCE_BUSY, name); | 81 | res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name); |
94 | 82 | ||
95 | if (res) { | 83 | if (res) { |
96 | #ifdef CONFIG_PCI | 84 | #ifdef CONFIG_PCI |
@@ -661,8 +649,9 @@ pcmcia_align(void *align_data, const struct resource *res, | |||
661 | * Adjust an existing IO region allocation, but making sure that we don't | 649 | * Adjust an existing IO region allocation, but making sure that we don't |
662 | * encroach outside the resources which the user supplied. | 650 | * encroach outside the resources which the user supplied. |
663 | */ | 651 | */ |
664 | static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start, | 652 | static int __nonstatic_adjust_io_region(struct pcmcia_socket *s, |
665 | unsigned long r_end, struct pcmcia_socket *s) | 653 | unsigned long r_start, |
654 | unsigned long r_end) | ||
666 | { | 655 | { |
667 | struct resource_map *m; | 656 | struct resource_map *m; |
668 | struct socket_data *s_data = s->resource_data; | 657 | struct socket_data *s_data = s->resource_data; |
@@ -675,8 +664,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
675 | if (start > r_start || r_end > end) | 664 | if (start > r_start || r_end > end) |
676 | continue; | 665 | continue; |
677 | 666 | ||
678 | ret = adjust_resource(res, r_start, r_end - r_start + 1); | 667 | ret = 0; |
679 | break; | ||
680 | } | 668 | } |
681 | 669 | ||
682 | return ret; | 670 | return ret; |
@@ -695,18 +683,17 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star | |||
695 | 683 | ||
696 | ======================================================================*/ | 684 | ======================================================================*/ |
697 | 685 | ||
698 | static struct resource *nonstatic_find_io_region(unsigned long base, int num, | 686 | static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s, |
699 | unsigned long align, struct pcmcia_socket *s) | 687 | unsigned long base, int num, |
688 | unsigned long align) | ||
700 | { | 689 | { |
701 | struct resource *res = make_resource(0, num, IORESOURCE_IO, dev_name(&s->dev)); | 690 | struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO, |
691 | dev_name(&s->dev)); | ||
702 | struct socket_data *s_data = s->resource_data; | 692 | struct socket_data *s_data = s->resource_data; |
703 | struct pcmcia_align_data data; | 693 | struct pcmcia_align_data data; |
704 | unsigned long min = base; | 694 | unsigned long min = base; |
705 | int ret; | 695 | int ret; |
706 | 696 | ||
707 | if (align == 0) | ||
708 | align = 0x10000; | ||
709 | |||
710 | data.mask = align - 1; | 697 | data.mask = align - 1; |
711 | data.offset = base & data.mask; | 698 | data.offset = base & data.mask; |
712 | data.map = &s_data->io_db; | 699 | data.map = &s_data->io_db; |
@@ -727,10 +714,97 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num, | |||
727 | return res; | 714 | return res; |
728 | } | 715 | } |
729 | 716 | ||
717 | static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr, | ||
718 | unsigned int *base, unsigned int num, | ||
719 | unsigned int align) | ||
720 | { | ||
721 | int i, ret = 0; | ||
722 | |||
723 | /* Check for an already-allocated window that must conflict with | ||
724 | * what was asked for. It is a hack because it does not catch all | ||
725 | * potential conflicts, just the most obvious ones. | ||
726 | */ | ||
727 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
728 | if (!s->io[i].res) | ||
729 | continue; | ||
730 | |||
731 | if (!*base) | ||
732 | continue; | ||
733 | |||
734 | if ((s->io[i].res->start & (align-1)) == *base) | ||
735 | return -EBUSY; | ||
736 | } | ||
737 | |||
738 | for (i = 0; i < MAX_IO_WIN; i++) { | ||
739 | struct resource *res = s->io[i].res; | ||
740 | unsigned int try; | ||
741 | |||
742 | if (res && (res->flags & IORESOURCE_BITS) != | ||
743 | (attr & IORESOURCE_BITS)) | ||
744 | continue; | ||
745 | |||
746 | if (!res) { | ||
747 | if (align == 0) | ||
748 | align = 0x10000; | ||
749 | |||
750 | res = s->io[i].res = __nonstatic_find_io_region(s, | ||
751 | *base, num, | ||
752 | align); | ||
753 | if (!res) | ||
754 | return -EINVAL; | ||
755 | |||
756 | *base = res->start; | ||
757 | s->io[i].res->flags = | ||
758 | ((res->flags & ~IORESOURCE_BITS) | | ||
759 | (attr & IORESOURCE_BITS)); | ||
760 | s->io[i].InUse = num; | ||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* Try to extend top of window */ | ||
765 | try = res->end + 1; | ||
766 | if ((*base == 0) || (*base == try)) { | ||
767 | ret = __nonstatic_adjust_io_region(s, res->start, | ||
768 | res->end + num); | ||
769 | if (!ret) { | ||
770 | ret = adjust_resource(s->io[i].res, res->start, | ||
771 | res->end - res->start + num + 1); | ||
772 | if (ret) | ||
773 | continue; | ||
774 | *base = try; | ||
775 | s->io[i].InUse += num; | ||
776 | return 0; | ||
777 | } | ||
778 | } | ||
779 | |||
780 | /* Try to extend bottom of window */ | ||
781 | try = res->start - num; | ||
782 | if ((*base == 0) || (*base == try)) { | ||
783 | ret = __nonstatic_adjust_io_region(s, | ||
784 | res->start - num, | ||
785 | res->end); | ||
786 | if (!ret) { | ||
787 | ret = adjust_resource(s->io[i].res, | ||
788 | res->start - num, | ||
789 | res->end - res->start + num + 1); | ||
790 | if (ret) | ||
791 | continue; | ||
792 | *base = try; | ||
793 | s->io[i].InUse += num; | ||
794 | return 0; | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | |||
799 | return -EINVAL; | ||
800 | } | ||
801 | |||
802 | |||
730 | static struct resource *nonstatic_find_mem_region(u_long base, u_long num, | 803 | static struct resource *nonstatic_find_mem_region(u_long base, u_long num, |
731 | u_long align, int low, struct pcmcia_socket *s) | 804 | u_long align, int low, struct pcmcia_socket *s) |
732 | { | 805 | { |
733 | struct resource *res = make_resource(0, num, IORESOURCE_MEM, dev_name(&s->dev)); | 806 | struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM, |
807 | dev_name(&s->dev)); | ||
734 | struct socket_data *s_data = s->resource_data; | 808 | struct socket_data *s_data = s->resource_data; |
735 | struct pcmcia_align_data data; | 809 | struct pcmcia_align_data data; |
736 | unsigned long min, max; | 810 | unsigned long min, max; |
@@ -861,23 +935,42 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) | |||
861 | return -ENODEV; | 935 | return -ENODEV; |
862 | 936 | ||
863 | #if defined(CONFIG_X86) | 937 | #if defined(CONFIG_X86) |
864 | /* If this is the root bus, the risk of hitting | 938 | /* If this is the root bus, the risk of hitting some strange |
865 | * some strange system devices which aren't protected | 939 | * system devices is too high: If a driver isn't loaded, the |
866 | * by either ACPI resource tables or properly requested | 940 | * resources are not claimed; even if a driver is loaded, it |
867 | * resources is too big. Therefore, don't do auto-adding | 941 | * may not request all resources or even the wrong one. We |
868 | * of resources at the moment. | 942 | * can neither trust the rest of the kernel nor ACPI/PNP and |
943 | * CRS parsing to get it right. Therefore, use several | ||
944 | * safeguards: | ||
945 | * | ||
946 | * - Do not auto-add resources if the CardBus bridge is on | ||
947 | * the PCI root bus | ||
948 | * | ||
949 | * - Avoid any I/O ports < 0x100. | ||
950 | * | ||
951 | * - On PCI-PCI bridges, only use resources which are set up | ||
952 | * exclusively for the secondary PCI bus: the risk of hitting | ||
953 | * system devices is quite low, as they usually aren't | ||
954 | * connected to the secondary PCI bus. | ||
869 | */ | 955 | */ |
870 | if (s->cb_dev->bus->number == 0) | 956 | if (s->cb_dev->bus->number == 0) |
871 | return -EINVAL; | 957 | return -EINVAL; |
872 | #endif | ||
873 | 958 | ||
959 | for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) { | ||
960 | res = s->cb_dev->bus->resource[i]; | ||
961 | #else | ||
874 | pci_bus_for_each_resource(s->cb_dev->bus, res, i) { | 962 | pci_bus_for_each_resource(s->cb_dev->bus, res, i) { |
963 | #endif | ||
875 | if (!res) | 964 | if (!res) |
876 | continue; | 965 | continue; |
877 | 966 | ||
878 | if (res->flags & IORESOURCE_IO) { | 967 | if (res->flags & IORESOURCE_IO) { |
968 | /* safeguard against the root resource, where the | ||
969 | * risk of hitting any other device would be too | ||
970 | * high */ | ||
879 | if (res == &ioport_resource) | 971 | if (res == &ioport_resource) |
880 | continue; | 972 | continue; |
973 | |||
881 | dev_printk(KERN_INFO, &s->cb_dev->dev, | 974 | dev_printk(KERN_INFO, &s->cb_dev->dev, |
882 | "pcmcia: parent PCI bridge window: %pR\n", | 975 | "pcmcia: parent PCI bridge window: %pR\n", |
883 | res); | 976 | res); |
@@ -887,8 +980,12 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s) | |||
887 | } | 980 | } |
888 | 981 | ||
889 | if (res->flags & IORESOURCE_MEM) { | 982 | if (res->flags & IORESOURCE_MEM) { |
983 | /* safeguard against the root resource, where the | ||
984 | * risk of hitting any other device would be too | ||
985 | * high */ | ||
890 | if (res == &iomem_resource) | 986 | if (res == &iomem_resource) |
891 | continue; | 987 | continue; |
988 | |||
892 | dev_printk(KERN_INFO, &s->cb_dev->dev, | 989 | dev_printk(KERN_INFO, &s->cb_dev->dev, |
893 | "pcmcia: parent PCI bridge window: %pR\n", | 990 | "pcmcia: parent PCI bridge window: %pR\n", |
894 | res); | 991 | res); |
@@ -956,8 +1053,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) | |||
956 | 1053 | ||
957 | struct pccard_resource_ops pccard_nonstatic_ops = { | 1054 | struct pccard_resource_ops pccard_nonstatic_ops = { |
958 | .validate_mem = pcmcia_nonstatic_validate_mem, | 1055 | .validate_mem = pcmcia_nonstatic_validate_mem, |
959 | .adjust_io_region = nonstatic_adjust_io_region, | 1056 | .find_io = nonstatic_find_io, |
960 | .find_io = nonstatic_find_io_region, | ||
961 | .find_mem = nonstatic_find_mem_region, | 1057 | .find_mem = nonstatic_find_mem_region, |
962 | .add_io = adjust_io, | 1058 | .add_io = adjust_io, |
963 | .add_mem = adjust_memory, | 1059 | .add_mem = adjust_memory, |