aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia/rsrc_nonstatic.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-20 12:09:46 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-20 12:09:46 -0400
commit54291263519ac2c9bdda68b23b02fef3808deed4 (patch)
treed71de8172a6ab2bbe3068aece7d8911eeeb276fd /drivers/pcmcia/rsrc_nonstatic.c
parent46ee9645094ad1eb5b4888882ecaa1fb87dcd2a3 (diff)
parentacd200bf45487271d54f05938ad9e30f32a530ee (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.c164
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
37MODULE_AUTHOR("David A. Hinds, Dominik Brodowski"); 38MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
38MODULE_LICENSE("GPL"); 39MODULE_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
72static struct resource * 74static struct resource *
73make_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
86static struct resource *
87claim_region(struct pcmcia_socket *s, resource_size_t base, 75claim_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 */
664static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start, 652static 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
698static struct resource *nonstatic_find_io_region(unsigned long base, int num, 686static 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
717static 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
730static struct resource *nonstatic_find_mem_region(u_long base, u_long num, 803static 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
957struct pccard_resource_ops pccard_nonstatic_ops = { 1054struct 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,