diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r-- | drivers/pci/setup-bus.c | 65 |
1 files changed, 44 insertions, 21 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index a7ba6de588a8..fb506137aaee 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c | |||
@@ -265,7 +265,7 @@ out: | |||
265 | * assign_requested_resources_sorted() - satisfy resource requests | 265 | * assign_requested_resources_sorted() - satisfy resource requests |
266 | * | 266 | * |
267 | * @head : head of the list tracking requests for resources | 267 | * @head : head of the list tracking requests for resources |
268 | * @failed_list : head of the list tracking requests that could | 268 | * @fail_head : head of the list tracking requests that could |
269 | * not be allocated | 269 | * not be allocated |
270 | * | 270 | * |
271 | * Satisfy resource requests of each element in the list. Add | 271 | * Satisfy resource requests of each element in the list. Add |
@@ -404,8 +404,8 @@ void pci_setup_cardbus(struct pci_bus *bus) | |||
404 | struct resource *res; | 404 | struct resource *res; |
405 | struct pci_bus_region region; | 405 | struct pci_bus_region region; |
406 | 406 | ||
407 | dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n", | 407 | dev_info(&bridge->dev, "CardBus bridge to %pR\n", |
408 | bus->secondary, bus->subordinate); | 408 | &bus->busn_res); |
409 | 409 | ||
410 | res = bus->resource[0]; | 410 | res = bus->resource[0]; |
411 | pcibios_resource_to_bus(bridge, ®ion, res); | 411 | pcibios_resource_to_bus(bridge, ®ion, res); |
@@ -469,16 +469,23 @@ static void pci_setup_bridge_io(struct pci_bus *bus) | |||
469 | struct pci_dev *bridge = bus->self; | 469 | struct pci_dev *bridge = bus->self; |
470 | struct resource *res; | 470 | struct resource *res; |
471 | struct pci_bus_region region; | 471 | struct pci_bus_region region; |
472 | unsigned long io_mask; | ||
473 | u8 io_base_lo, io_limit_lo; | ||
472 | u32 l, io_upper16; | 474 | u32 l, io_upper16; |
473 | 475 | ||
476 | io_mask = PCI_IO_RANGE_MASK; | ||
477 | if (bridge->io_window_1k) | ||
478 | io_mask = PCI_IO_1K_RANGE_MASK; | ||
479 | |||
474 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ | 480 | /* Set up the top and bottom of the PCI I/O segment for this bus. */ |
475 | res = bus->resource[0]; | 481 | res = bus->resource[0]; |
476 | pcibios_resource_to_bus(bridge, ®ion, res); | 482 | pcibios_resource_to_bus(bridge, ®ion, res); |
477 | if (res->flags & IORESOURCE_IO) { | 483 | if (res->flags & IORESOURCE_IO) { |
478 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); | 484 | pci_read_config_dword(bridge, PCI_IO_BASE, &l); |
479 | l &= 0xffff0000; | 485 | l &= 0xffff0000; |
480 | l |= (region.start >> 8) & 0x00f0; | 486 | io_base_lo = (region.start >> 8) & io_mask; |
481 | l |= region.end & 0xf000; | 487 | io_limit_lo = (region.end >> 8) & io_mask; |
488 | l |= ((u32) io_limit_lo << 8) | io_base_lo; | ||
482 | /* Set up upper 16 bits of I/O base/limit. */ | 489 | /* Set up upper 16 bits of I/O base/limit. */ |
483 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); | 490 | io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); |
484 | dev_info(&bridge->dev, " bridge window %pR\n", res); | 491 | dev_info(&bridge->dev, " bridge window %pR\n", res); |
@@ -553,8 +560,8 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type) | |||
553 | { | 560 | { |
554 | struct pci_dev *bridge = bus->self; | 561 | struct pci_dev *bridge = bus->self; |
555 | 562 | ||
556 | dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", | 563 | dev_info(&bridge->dev, "PCI bridge to %pR\n", |
557 | bus->secondary, bus->subordinate); | 564 | &bus->busn_res); |
558 | 565 | ||
559 | if (type & IORESOURCE_IO) | 566 | if (type & IORESOURCE_IO) |
560 | pci_setup_bridge_io(bus); | 567 | pci_setup_bridge_io(bus); |
@@ -699,7 +706,7 @@ static resource_size_t calculate_memsize(resource_size_t size, | |||
699 | * @realloc_head : track the additional io window on this list | 706 | * @realloc_head : track the additional io window on this list |
700 | * | 707 | * |
701 | * Sizing the IO windows of the PCI-PCI bridge is trivial, | 708 | * Sizing the IO windows of the PCI-PCI bridge is trivial, |
702 | * since these windows have 4K granularity and the IO ranges | 709 | * since these windows have 1K or 4K granularity and the IO ranges |
703 | * of non-bridge PCI devices are limited to 256 bytes. | 710 | * of non-bridge PCI devices are limited to 256 bytes. |
704 | * We must be careful with the ISA aliasing though. | 711 | * We must be careful with the ISA aliasing though. |
705 | */ | 712 | */ |
@@ -710,10 +717,17 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
710 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); | 717 | struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); |
711 | unsigned long size = 0, size0 = 0, size1 = 0; | 718 | unsigned long size = 0, size0 = 0, size1 = 0; |
712 | resource_size_t children_add_size = 0; | 719 | resource_size_t children_add_size = 0; |
720 | resource_size_t min_align = 4096, align; | ||
713 | 721 | ||
714 | if (!b_res) | 722 | if (!b_res) |
715 | return; | 723 | return; |
716 | 724 | ||
725 | /* | ||
726 | * Per spec, I/O windows are 4K-aligned, but some bridges have an | ||
727 | * extension to support 1K alignment. | ||
728 | */ | ||
729 | if (bus->self->io_window_1k) | ||
730 | min_align = 1024; | ||
717 | list_for_each_entry(dev, &bus->devices, bus_list) { | 731 | list_for_each_entry(dev, &bus->devices, bus_list) { |
718 | int i; | 732 | int i; |
719 | 733 | ||
@@ -731,34 +745,43 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, | |||
731 | else | 745 | else |
732 | size1 += r_size; | 746 | size1 += r_size; |
733 | 747 | ||
748 | align = pci_resource_alignment(dev, r); | ||
749 | if (align > min_align) | ||
750 | min_align = align; | ||
751 | |||
734 | if (realloc_head) | 752 | if (realloc_head) |
735 | children_add_size += get_res_add_size(realloc_head, r); | 753 | children_add_size += get_res_add_size(realloc_head, r); |
736 | } | 754 | } |
737 | } | 755 | } |
756 | |||
757 | if (min_align > 4096) | ||
758 | min_align = 4096; | ||
759 | |||
738 | size0 = calculate_iosize(size, min_size, size1, | 760 | size0 = calculate_iosize(size, min_size, size1, |
739 | resource_size(b_res), 4096); | 761 | resource_size(b_res), min_align); |
740 | if (children_add_size > add_size) | 762 | if (children_add_size > add_size) |
741 | add_size = children_add_size; | 763 | add_size = children_add_size; |
742 | size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : | 764 | size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : |
743 | calculate_iosize(size, min_size, add_size + size1, | 765 | calculate_iosize(size, min_size, add_size + size1, |
744 | resource_size(b_res), 4096); | 766 | resource_size(b_res), min_align); |
745 | if (!size0 && !size1) { | 767 | if (!size0 && !size1) { |
746 | if (b_res->start || b_res->end) | 768 | if (b_res->start || b_res->end) |
747 | dev_info(&bus->self->dev, "disabling bridge window " | 769 | dev_info(&bus->self->dev, "disabling bridge window " |
748 | "%pR to [bus %02x-%02x] (unused)\n", b_res, | 770 | "%pR to %pR (unused)\n", b_res, |
749 | bus->secondary, bus->subordinate); | 771 | &bus->busn_res); |
750 | b_res->flags = 0; | 772 | b_res->flags = 0; |
751 | return; | 773 | return; |
752 | } | 774 | } |
753 | /* Alignment of the IO window is always 4K */ | 775 | |
754 | b_res->start = 4096; | 776 | b_res->start = min_align; |
755 | b_res->end = b_res->start + size0 - 1; | 777 | b_res->end = b_res->start + size0 - 1; |
756 | b_res->flags |= IORESOURCE_STARTALIGN; | 778 | b_res->flags |= IORESOURCE_STARTALIGN; |
757 | if (size1 > size0 && realloc_head) { | 779 | if (size1 > size0 && realloc_head) { |
758 | add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096); | 780 | add_to_list(realloc_head, bus->self, b_res, size1-size0, |
781 | min_align); | ||
759 | dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " | 782 | dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " |
760 | "%pR to [bus %02x-%02x] add_size %lx\n", b_res, | 783 | "%pR to %pR add_size %lx\n", b_res, |
761 | bus->secondary, bus->subordinate, size1-size0); | 784 | &bus->busn_res, size1-size0); |
762 | } | 785 | } |
763 | } | 786 | } |
764 | 787 | ||
@@ -863,8 +886,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
863 | if (!size0 && !size1) { | 886 | if (!size0 && !size1) { |
864 | if (b_res->start || b_res->end) | 887 | if (b_res->start || b_res->end) |
865 | dev_info(&bus->self->dev, "disabling bridge window " | 888 | dev_info(&bus->self->dev, "disabling bridge window " |
866 | "%pR to [bus %02x-%02x] (unused)\n", b_res, | 889 | "%pR to %pR (unused)\n", b_res, |
867 | bus->secondary, bus->subordinate); | 890 | &bus->busn_res); |
868 | b_res->flags = 0; | 891 | b_res->flags = 0; |
869 | return 1; | 892 | return 1; |
870 | } | 893 | } |
@@ -874,8 +897,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, | |||
874 | if (size1 > size0 && realloc_head) { | 897 | if (size1 > size0 && realloc_head) { |
875 | add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); | 898 | add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); |
876 | dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " | 899 | dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " |
877 | "%pR to [bus %02x-%02x] add_size %llx\n", b_res, | 900 | "%pR to %pR add_size %llx\n", b_res, |
878 | bus->secondary, bus->subordinate, (unsigned long long)size1-size0); | 901 | &bus->busn_res, (unsigned long long)size1-size0); |
879 | } | 902 | } |
880 | return 1; | 903 | return 1; |
881 | } | 904 | } |