diff options
| author | Dominik Brodowski <linux@dominikbrodowski.net> | 2005-07-12 16:58:17 -0400 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-12 19:01:00 -0400 | 
| commit | eb0a90b4970d667e9ae9df538710f12b8e78e442 (patch) | |
| tree | 341f050368edbe235e3515032d5b6797545b7745 | |
| parent | 278798357d4a8658067dc9ac399d8ffba8389f03 (diff) | |
[PATCH] yenta: allocate resource fixes
The current CardBus window allocation code in yenta_socket is unable to handle
the transparent PCI-bridge handling update in 2.6.13.  We need to check _all_
resources of a given type to find the best one suitable for CardBus windows,
not just the first one.
Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -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 | /* | 
