diff options
| -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 | /* |
