diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/yenta_socket.c | 126 |
1 files changed, 88 insertions, 38 deletions
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index d3807e22fe04..f9d2367b6bdf 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c | |||
@@ -527,24 +527,87 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock) | |||
527 | * Use an adaptive allocation for the memory resource, | 527 | * Use an adaptive allocation for the memory resource, |
528 | * sometimes the memory behind pci bridges is limited: | 528 | * sometimes the memory behind pci bridges is limited: |
529 | * 1/8 of the size of the io window of the parent. | 529 | * 1/8 of the size of the io window of the parent. |
530 | * max 4 MB, min 16 kB. | 530 | * max 4 MB, min 16 kB. We try very hard to not get below |
531 | * the "ACC" values, though. | ||
531 | */ | 532 | */ |
532 | #define BRIDGE_MEM_MAX 4*1024*1024 | 533 | #define BRIDGE_MEM_MAX 4*1024*1024 |
534 | #define BRIDGE_MEM_ACC 128*1024 | ||
533 | #define BRIDGE_MEM_MIN 16*1024 | 535 | #define BRIDGE_MEM_MIN 16*1024 |
534 | 536 | ||
535 | #define BRIDGE_IO_MAX 256 | 537 | #define BRIDGE_IO_MAX 512 |
538 | #define BRIDGE_IO_ACC 256 | ||
536 | #define BRIDGE_IO_MIN 32 | 539 | #define BRIDGE_IO_MIN 32 |
537 | 540 | ||
538 | #ifndef PCIBIOS_MIN_CARDBUS_IO | 541 | #ifndef PCIBIOS_MIN_CARDBUS_IO |
539 | #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO | 542 | #define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO |
540 | #endif | 543 | #endif |
541 | 544 | ||
545 | static int yenta_search_one_res(struct resource *root, struct resource *res, | ||
546 | u32 min) | ||
547 | { | ||
548 | u32 align, size, start, end; | ||
549 | |||
550 | if (res->flags & IORESOURCE_IO) { | ||
551 | align = 1024; | ||
552 | size = BRIDGE_IO_MAX; | ||
553 | start = PCIBIOS_MIN_CARDBUS_IO; | ||
554 | end = ~0U; | ||
555 | } else { | ||
556 | unsigned long avail = root->end - root->start; | ||
557 | int i; | ||
558 | size = BRIDGE_MEM_MAX; | ||
559 | if (size > avail/8) { | ||
560 | size=(avail+1)/8; | ||
561 | /* round size down to next power of 2 */ | ||
562 | i = 0; | ||
563 | while ((size /= 2) != 0) | ||
564 | i++; | ||
565 | size = 1 << i; | ||
566 | } | ||
567 | if (size < min) | ||
568 | size = min; | ||
569 | align = size; | ||
570 | start = PCIBIOS_MIN_MEM; | ||
571 | end = ~0U; | ||
572 | } | ||
573 | |||
574 | do { | ||
575 | if (allocate_resource(root, res, size, start, end, align, | ||
576 | NULL, NULL)==0) { | ||
577 | return 1; | ||
578 | } | ||
579 | size = size/2; | ||
580 | align = size; | ||
581 | } while (size >= min); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | |||
587 | static int yenta_search_res(struct yenta_socket *socket, struct resource *res, | ||
588 | u32 min) | ||
589 | { | ||
590 | int i; | ||
591 | for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) { | ||
592 | struct resource * root = socket->dev->bus->resource[i]; | ||
593 | if (!root) | ||
594 | continue; | ||
595 | |||
596 | if ((res->flags ^ root->flags) & | ||
597 | (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH)) | ||
598 | continue; /* Wrong type */ | ||
599 | |||
600 | if (yenta_search_one_res(root, res, min)) | ||
601 | return 1; | ||
602 | } | ||
603 | return 0; | ||
604 | } | ||
605 | |||
542 | static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) | 606 | static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) |
543 | { | 607 | { |
544 | struct pci_bus *bus; | 608 | struct pci_bus *bus; |
545 | struct resource *root, *res; | 609 | struct resource *root, *res; |
546 | u32 start, end; | 610 | u32 start, end; |
547 | u32 align, size, min; | ||
548 | unsigned mask; | 611 | unsigned mask; |
549 | 612 | ||
550 | res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; | 613 | res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; |
@@ -573,48 +636,35 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ | |||
573 | pci_name(socket->dev), nr); | 636 | pci_name(socket->dev), nr); |
574 | } | 637 | } |
575 | 638 | ||
576 | res->start = 0; | ||
577 | res->end = 0; | ||
578 | root = pci_find_parent_resource(socket->dev, res); | ||
579 | |||
580 | if (type & IORESOURCE_IO) { | 639 | if (type & IORESOURCE_IO) { |
581 | align = 1024; | 640 | if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) || |
582 | size = BRIDGE_IO_MAX; | 641 | (yenta_search_res(socket, res, BRIDGE_IO_ACC)) || |
583 | min = BRIDGE_IO_MIN; | 642 | (yenta_search_res(socket, res, BRIDGE_IO_MIN))) { |
584 | start = PCIBIOS_MIN_CARDBUS_IO; | 643 | config_writel(socket, addr_start, res->start); |
585 | end = ~0U; | 644 | config_writel(socket, addr_end, res->end); |
645 | } | ||
586 | } else { | 646 | } else { |
587 | unsigned long avail = root->end - root->start; | 647 | if (type & IORESOURCE_PREFETCH) { |
588 | int i; | 648 | if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || |
589 | size = BRIDGE_MEM_MAX; | 649 | (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || |
590 | if (size > avail/8) { | 650 | (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { |
591 | size=(avail+1)/8; | 651 | config_writel(socket, addr_start, res->start); |
592 | /* round size down to next power of 2 */ | 652 | config_writel(socket, addr_end, res->end); |
593 | i = 0; | 653 | } |
594 | while ((size /= 2) != 0) | 654 | /* Approximating prefetchable by non-prefetchable */ |
595 | i++; | 655 | res->flags = IORESOURCE_MEM; |
596 | size = 1 << i; | ||
597 | } | 656 | } |
598 | if (size < BRIDGE_MEM_MIN) | 657 | if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || |
599 | size = BRIDGE_MEM_MIN; | 658 | (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || |
600 | min = BRIDGE_MEM_MIN; | 659 | (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { |
601 | align = size; | ||
602 | start = PCIBIOS_MIN_MEM; | ||
603 | end = ~0U; | ||
604 | } | ||
605 | |||
606 | do { | ||
607 | if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) { | ||
608 | config_writel(socket, addr_start, res->start); | 660 | config_writel(socket, addr_start, res->start); |
609 | config_writel(socket, addr_end, res->end); | 661 | config_writel(socket, addr_end, res->end); |
610 | return; | ||
611 | } | 662 | } |
612 | size = size/2; | 663 | } |
613 | align = size; | 664 | |
614 | } while (size >= min); | ||
615 | printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", | 665 | printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", |
616 | pci_name(socket->dev), type); | 666 | pci_name(socket->dev), type); |
617 | res->start = res->end = 0; | 667 | res->start = res->end = res->flags = 0; |
618 | } | 668 | } |
619 | 669 | ||
620 | /* | 670 | /* |