diff options
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a3b0a5eb5054..0eeac60042b3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -679,6 +679,33 @@ static int pci_setup_device(struct pci_dev * dev) | |||
679 | pci_read_bases(dev, 6, PCI_ROM_ADDRESS); | 679 | pci_read_bases(dev, 6, PCI_ROM_ADDRESS); |
680 | pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); | 680 | pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor); |
681 | pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); | 681 | pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device); |
682 | |||
683 | /* | ||
684 | * Do the ugly legacy mode stuff here rather than broken chip | ||
685 | * quirk code. Legacy mode ATA controllers have fixed | ||
686 | * addresses. These are not always echoed in BAR0-3, and | ||
687 | * BAR0-3 in a few cases contain junk! | ||
688 | */ | ||
689 | if (class == PCI_CLASS_STORAGE_IDE) { | ||
690 | u8 progif; | ||
691 | pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); | ||
692 | if ((progif & 1) == 0) { | ||
693 | dev->resource[0].start = 0x1F0; | ||
694 | dev->resource[0].end = 0x1F7; | ||
695 | dev->resource[0].flags = IORESOURCE_IO; | ||
696 | dev->resource[1].start = 0x3F6; | ||
697 | dev->resource[1].end = 0x3F6; | ||
698 | dev->resource[1].flags = IORESOURCE_IO; | ||
699 | } | ||
700 | if ((progif & 4) == 0) { | ||
701 | dev->resource[2].start = 0x170; | ||
702 | dev->resource[2].end = 0x177; | ||
703 | dev->resource[2].flags = IORESOURCE_IO; | ||
704 | dev->resource[3].start = 0x376; | ||
705 | dev->resource[3].end = 0x376; | ||
706 | dev->resource[3].flags = IORESOURCE_IO; | ||
707 | } | ||
708 | } | ||
682 | break; | 709 | break; |
683 | 710 | ||
684 | case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ | 711 | case PCI_HEADER_TYPE_BRIDGE: /* bridge header */ |
@@ -1067,3 +1094,95 @@ EXPORT_SYMBOL(pci_scan_bridge); | |||
1067 | EXPORT_SYMBOL(pci_scan_single_device); | 1094 | EXPORT_SYMBOL(pci_scan_single_device); |
1068 | EXPORT_SYMBOL_GPL(pci_scan_child_bus); | 1095 | EXPORT_SYMBOL_GPL(pci_scan_child_bus); |
1069 | #endif | 1096 | #endif |
1097 | |||
1098 | static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b) | ||
1099 | { | ||
1100 | if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1; | ||
1101 | else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1; | ||
1102 | |||
1103 | if (a->bus->number < b->bus->number) return -1; | ||
1104 | else if (a->bus->number > b->bus->number) return 1; | ||
1105 | |||
1106 | if (a->devfn < b->devfn) return -1; | ||
1107 | else if (a->devfn > b->devfn) return 1; | ||
1108 | |||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | /* | ||
1113 | * Yes, this forcably breaks the klist abstraction temporarily. It | ||
1114 | * just wants to sort the klist, not change reference counts and | ||
1115 | * take/drop locks rapidly in the process. It does all this while | ||
1116 | * holding the lock for the list, so objects can't otherwise be | ||
1117 | * added/removed while we're swizzling. | ||
1118 | */ | ||
1119 | static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list) | ||
1120 | { | ||
1121 | struct list_head *pos; | ||
1122 | struct klist_node *n; | ||
1123 | struct device *dev; | ||
1124 | struct pci_dev *b; | ||
1125 | |||
1126 | list_for_each(pos, list) { | ||
1127 | n = container_of(pos, struct klist_node, n_node); | ||
1128 | dev = container_of(n, struct device, knode_bus); | ||
1129 | b = to_pci_dev(dev); | ||
1130 | if (pci_sort_bf_cmp(a, b) <= 0) { | ||
1131 | list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node); | ||
1132 | return; | ||
1133 | } | ||
1134 | } | ||
1135 | list_move_tail(&a->dev.knode_bus.n_node, list); | ||
1136 | } | ||
1137 | |||
1138 | static void __init pci_sort_breadthfirst_klist(void) | ||
1139 | { | ||
1140 | LIST_HEAD(sorted_devices); | ||
1141 | struct list_head *pos, *tmp; | ||
1142 | struct klist_node *n; | ||
1143 | struct device *dev; | ||
1144 | struct pci_dev *pdev; | ||
1145 | |||
1146 | spin_lock(&pci_bus_type.klist_devices.k_lock); | ||
1147 | list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) { | ||
1148 | n = container_of(pos, struct klist_node, n_node); | ||
1149 | dev = container_of(n, struct device, knode_bus); | ||
1150 | pdev = to_pci_dev(dev); | ||
1151 | pci_insertion_sort_klist(pdev, &sorted_devices); | ||
1152 | } | ||
1153 | list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list); | ||
1154 | spin_unlock(&pci_bus_type.klist_devices.k_lock); | ||
1155 | } | ||
1156 | |||
1157 | static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list) | ||
1158 | { | ||
1159 | struct pci_dev *b; | ||
1160 | |||
1161 | list_for_each_entry(b, list, global_list) { | ||
1162 | if (pci_sort_bf_cmp(a, b) <= 0) { | ||
1163 | list_move_tail(&a->global_list, &b->global_list); | ||
1164 | return; | ||
1165 | } | ||
1166 | } | ||
1167 | list_move_tail(&a->global_list, list); | ||
1168 | } | ||
1169 | |||
1170 | static void __init pci_sort_breadthfirst_devices(void) | ||
1171 | { | ||
1172 | LIST_HEAD(sorted_devices); | ||
1173 | struct pci_dev *dev, *tmp; | ||
1174 | |||
1175 | down_write(&pci_bus_sem); | ||
1176 | list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) { | ||
1177 | pci_insertion_sort_devices(dev, &sorted_devices); | ||
1178 | } | ||
1179 | list_splice(&sorted_devices, &pci_devices); | ||
1180 | up_write(&pci_bus_sem); | ||
1181 | } | ||
1182 | |||
1183 | void __init pci_sort_breadthfirst(void) | ||
1184 | { | ||
1185 | pci_sort_breadthfirst_devices(); | ||
1186 | pci_sort_breadthfirst_klist(); | ||
1187 | } | ||
1188 | |||