diff options
Diffstat (limited to 'drivers/pcmcia/rsrc_nonstatic.c')
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index a06881c3b962..a69eed6c5b92 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -55,8 +55,8 @@ struct resource_map { | |||
55 | 55 | ||
56 | struct socket_data { | 56 | struct socket_data { |
57 | struct resource_map mem_db; | 57 | struct resource_map mem_db; |
58 | struct resource_map mem_db_valid; | ||
58 | struct resource_map io_db; | 59 | struct resource_map io_db; |
59 | unsigned int rsrc_mem_probe; | ||
60 | }; | 60 | }; |
61 | 61 | ||
62 | #define MEM_PROBE_LOW (1 << 0) | 62 | #define MEM_PROBE_LOW (1 << 0) |
@@ -357,6 +357,7 @@ static int do_validate_mem(struct pcmcia_socket *s, | |||
357 | struct resource *res, | 357 | struct resource *res, |
358 | unsigned int *value)) | 358 | unsigned int *value)) |
359 | { | 359 | { |
360 | struct socket_data *s_data = s->resource_data; | ||
360 | struct resource *res1, *res2; | 361 | struct resource *res1, *res2; |
361 | unsigned int info1 = 1, info2 = 1; | 362 | unsigned int info1 = 1, info2 = 1; |
362 | int ret = -EINVAL; | 363 | int ret = -EINVAL; |
@@ -382,6 +383,12 @@ static int do_validate_mem(struct pcmcia_socket *s, | |||
382 | if ((ret) || (info1 != info2) || (info1 == 0)) | 383 | if ((ret) || (info1 != info2) || (info1 == 0)) |
383 | return -EINVAL; | 384 | return -EINVAL; |
384 | 385 | ||
386 | if (validate && !s->fake_cis) { | ||
387 | /* move it to the validated data set */ | ||
388 | add_interval(&s_data->mem_db_valid, base, size); | ||
389 | sub_interval(&s_data->mem_db, base, size); | ||
390 | } | ||
391 | |||
385 | return 0; | 392 | return 0; |
386 | } | 393 | } |
387 | 394 | ||
@@ -491,6 +498,8 @@ static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
491 | if (probe_mask & MEM_PROBE_HIGH) { | 498 | if (probe_mask & MEM_PROBE_HIGH) { |
492 | if (inv_probe(s_data->mem_db.next, s) > 0) | 499 | if (inv_probe(s_data->mem_db.next, s) > 0) |
493 | return 0; | 500 | return 0; |
501 | if (s_data->mem_db_valid.next != &s_data->mem_db_valid) | ||
502 | return 0; | ||
494 | dev_printk(KERN_NOTICE, &s->dev, | 503 | dev_printk(KERN_NOTICE, &s->dev, |
495 | "cs: warning: no high memory space available!\n"); | 504 | "cs: warning: no high memory space available!\n"); |
496 | return -ENODEV; | 505 | return -ENODEV; |
@@ -565,21 +574,18 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | |||
565 | { | 574 | { |
566 | struct socket_data *s_data = s->resource_data; | 575 | struct socket_data *s_data = s->resource_data; |
567 | unsigned int probe_mask = MEM_PROBE_LOW; | 576 | unsigned int probe_mask = MEM_PROBE_LOW; |
568 | int ret = 0; | 577 | int ret; |
569 | 578 | ||
570 | if (!probe_mem) | 579 | if (!probe_mem || !(s->state & SOCKET_PRESENT)) |
571 | return 0; | 580 | return 0; |
572 | 581 | ||
573 | if (s->features & SS_CAP_PAGE_REGS) | 582 | if (s->features & SS_CAP_PAGE_REGS) |
574 | probe_mask = MEM_PROBE_HIGH; | 583 | probe_mask = MEM_PROBE_HIGH; |
575 | 584 | ||
576 | if (probe_mask & ~s_data->rsrc_mem_probe) { | 585 | ret = validate_mem(s, probe_mask); |
577 | if (s->state & SOCKET_PRESENT) { | 586 | |
578 | ret = validate_mem(s, probe_mask); | 587 | if (s_data->mem_db_valid.next != &s_data->mem_db_valid) |
579 | if (!ret) | 588 | return 0; |
580 | s_data->rsrc_mem_probe |= probe_mask; | ||
581 | } | ||
582 | } | ||
583 | 589 | ||
584 | return ret; | 590 | return ret; |
585 | } | 591 | } |
@@ -723,15 +729,15 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num, | |||
723 | struct socket_data *s_data = s->resource_data; | 729 | struct socket_data *s_data = s->resource_data; |
724 | struct pcmcia_align_data data; | 730 | struct pcmcia_align_data data; |
725 | unsigned long min, max; | 731 | unsigned long min, max; |
726 | int ret, i; | 732 | int ret, i, j; |
727 | 733 | ||
728 | low = low || !(s->features & SS_CAP_PAGE_REGS); | 734 | low = low || !(s->features & SS_CAP_PAGE_REGS); |
729 | 735 | ||
730 | data.mask = align - 1; | 736 | data.mask = align - 1; |
731 | data.offset = base & data.mask; | 737 | data.offset = base & data.mask; |
732 | data.map = &s_data->mem_db; | ||
733 | 738 | ||
734 | for (i = 0; i < 2; i++) { | 739 | for (i = 0; i < 2; i++) { |
740 | data.map = &s_data->mem_db_valid; | ||
735 | if (low) { | 741 | if (low) { |
736 | max = 0x100000UL; | 742 | max = 0x100000UL; |
737 | min = base < max ? base : 0; | 743 | min = base < max ? base : 0; |
@@ -740,15 +746,23 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num, | |||
740 | min = 0x100000UL + base; | 746 | min = 0x100000UL + base; |
741 | } | 747 | } |
742 | 748 | ||
749 | for (j = 0; j < 2; j++) { | ||
743 | #ifdef CONFIG_PCI | 750 | #ifdef CONFIG_PCI |
744 | if (s->cb_dev) { | 751 | if (s->cb_dev) { |
745 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, | 752 | ret = pci_bus_alloc_resource(s->cb_dev->bus, |
746 | 1, min, 0, | 753 | res, num, 1, min, 0, |
747 | pcmcia_align, &data); | 754 | pcmcia_align, &data); |
748 | } else | 755 | } else |
749 | #endif | 756 | #endif |
750 | ret = allocate_resource(&iomem_resource, res, num, min, | 757 | { |
751 | max, 1, pcmcia_align, &data); | 758 | ret = allocate_resource(&iomem_resource, |
759 | res, num, min, max, 1, | ||
760 | pcmcia_align, &data); | ||
761 | } | ||
762 | if (ret == 0) | ||
763 | break; | ||
764 | data.map = &s_data->mem_db; | ||
765 | } | ||
752 | if (ret == 0 || low) | 766 | if (ret == 0 || low) |
753 | break; | 767 | break; |
754 | low = 1; | 768 | low = 1; |
@@ -901,6 +915,7 @@ static int nonstatic_init(struct pcmcia_socket *s) | |||
901 | return -ENOMEM; | 915 | return -ENOMEM; |
902 | 916 | ||
903 | data->mem_db.next = &data->mem_db; | 917 | data->mem_db.next = &data->mem_db; |
918 | data->mem_db_valid.next = &data->mem_db_valid; | ||
904 | data->io_db.next = &data->io_db; | 919 | data->io_db.next = &data->io_db; |
905 | 920 | ||
906 | s->resource_data = (void *) data; | 921 | s->resource_data = (void *) data; |
@@ -915,6 +930,10 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s) | |||
915 | struct socket_data *data = s->resource_data; | 930 | struct socket_data *data = s->resource_data; |
916 | struct resource_map *p, *q; | 931 | struct resource_map *p, *q; |
917 | 932 | ||
933 | for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) { | ||
934 | q = p->next; | ||
935 | kfree(p); | ||
936 | } | ||
918 | for (p = data->mem_db.next; p != &data->mem_db; p = q) { | 937 | for (p = data->mem_db.next; p != &data->mem_db; p = q) { |
919 | q = p->next; | 938 | q = p->next; |
920 | kfree(p); | 939 | kfree(p); |
@@ -1010,6 +1029,16 @@ static ssize_t show_mem_db(struct device *dev, | |||
1010 | mutex_lock(&s->ops_mutex); | 1029 | mutex_lock(&s->ops_mutex); |
1011 | data = s->resource_data; | 1030 | data = s->resource_data; |
1012 | 1031 | ||
1032 | for (p = data->mem_db_valid.next; p != &data->mem_db_valid; | ||
1033 | p = p->next) { | ||
1034 | if (ret > (PAGE_SIZE - 10)) | ||
1035 | continue; | ||
1036 | ret += snprintf(&buf[ret], (PAGE_SIZE - ret - 1), | ||
1037 | "0x%08lx - 0x%08lx\n", | ||
1038 | ((unsigned long) p->base), | ||
1039 | ((unsigned long) p->base + p->num - 1)); | ||
1040 | } | ||
1041 | |||
1013 | for (p = data->mem_db.next; p != &data->mem_db; p = p->next) { | 1042 | for (p = data->mem_db.next; p != &data->mem_db; p = p->next) { |
1014 | if (ret > (PAGE_SIZE - 10)) | 1043 | if (ret > (PAGE_SIZE - 10)) |
1015 | continue; | 1044 | continue; |