Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Compaq Hot Plug Controller Driver | |
3 | * | |
4 | * Copyright (C) 1995,2001 Compaq Computer Corporation | |
5 | * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) | |
6 | * Copyright (C) 2001 IBM Corp. | |
7 | * | |
8 | * All rights reserved. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or (at | |
13 | * your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, but | |
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | |
18 | * NON INFRINGEMENT. See the GNU General Public License for more | |
19 | * details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 | * | |
25 | * Send feedback to <greg@kroah.com> | |
26 | * | |
27 | */ | |
28 | ||
1da177e4 LT |
29 | #include <linux/module.h> |
30 | #include <linux/kernel.h> | |
31 | #include <linux/types.h> | |
32 | #include <linux/slab.h> | |
33 | #include <linux/workqueue.h> | |
34 | #include <linux/proc_fs.h> | |
35 | #include <linux/pci.h> | |
7a54f25c | 36 | #include <linux/pci_hotplug.h> |
1da177e4 LT |
37 | #include "../pci.h" |
38 | #include "cpqphp.h" | |
39 | #include "cpqphp_nvram.h" | |
1da177e4 LT |
40 | |
41 | ||
42 | u8 cpqhp_nic_irq; | |
43 | u8 cpqhp_disk_irq; | |
44 | ||
45 | static u16 unused_IRQ; | |
46 | ||
47 | /* | |
48 | * detect_HRT_floating_pointer | |
49 | * | |
50 | * find the Hot Plug Resource Table in the specified region of memory. | |
51 | * | |
52 | */ | |
53 | static void __iomem *detect_HRT_floating_pointer(void __iomem *begin, void __iomem *end) | |
54 | { | |
55 | void __iomem *fp; | |
56 | void __iomem *endp; | |
57 | u8 temp1, temp2, temp3, temp4; | |
58 | int status = 0; | |
59 | ||
60 | endp = (end - sizeof(struct hrt) + 1); | |
61 | ||
62 | for (fp = begin; fp <= endp; fp += 16) { | |
63 | temp1 = readb(fp + SIG0); | |
64 | temp2 = readb(fp + SIG1); | |
65 | temp3 = readb(fp + SIG2); | |
66 | temp4 = readb(fp + SIG3); | |
67 | if (temp1 == '$' && | |
68 | temp2 == 'H' && | |
69 | temp3 == 'R' && | |
70 | temp4 == 'T') { | |
71 | status = 1; | |
72 | break; | |
73 | } | |
74 | } | |
75 | ||
76 | if (!status) | |
77 | fp = NULL; | |
78 | ||
79 | dbg("Discovered Hotplug Resource Table at %p\n", fp); | |
80 | return fp; | |
81 | } | |
82 | ||
83 | ||
861fefbf | 84 | int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) |
1da177e4 LT |
85 | { |
86 | unsigned char bus; | |
87 | struct pci_bus *child; | |
88 | int num; | |
89 | ||
90 | if (func->pci_dev == NULL) | |
12a9da0f | 91 | func->pci_dev = pci_get_bus_and_slot(func->bus,PCI_DEVFN(func->device, func->function)); |
1da177e4 LT |
92 | |
93 | /* No pci device, we need to create it then */ | |
94 | if (func->pci_dev == NULL) { | |
95 | dbg("INFO: pci_dev still null\n"); | |
96 | ||
97 | num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function)); | |
98 | if (num) | |
99 | pci_bus_add_devices(ctrl->pci_dev->bus); | |
100 | ||
12a9da0f | 101 | func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function)); |
1da177e4 LT |
102 | if (func->pci_dev == NULL) { |
103 | dbg("ERROR: pci_dev still null\n"); | |
104 | return 0; | |
105 | } | |
106 | } | |
107 | ||
108 | if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { | |
109 | pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); | |
110 | child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); | |
111 | pci_do_scan_bus(child); | |
112 | } | |
113 | ||
12a9da0f AC |
114 | pci_dev_put(func->pci_dev); |
115 | ||
1da177e4 LT |
116 | return 0; |
117 | } | |
118 | ||
119 | ||
861fefbf | 120 | int cpqhp_unconfigure_device(struct pci_func* func) |
1da177e4 LT |
121 | { |
122 | int j; | |
861fefbf | 123 | |
66bef8c0 | 124 | dbg("%s: bus/dev/func = %x/%x/%x\n", __func__, func->bus, func->device, func->function); |
1da177e4 LT |
125 | |
126 | for (j=0; j<8 ; j++) { | |
12a9da0f AC |
127 | struct pci_dev* temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j)); |
128 | if (temp) { | |
129 | pci_dev_put(temp); | |
1da177e4 | 130 | pci_remove_bus_device(temp); |
12a9da0f | 131 | } |
1da177e4 LT |
132 | } |
133 | return 0; | |
134 | } | |
135 | ||
136 | static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value) | |
137 | { | |
138 | u32 vendID = 0; | |
139 | ||
140 | if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1) | |
141 | return -1; | |
142 | if (vendID == 0xffffffff) | |
143 | return -1; | |
144 | return pci_bus_read_config_dword (bus, devfn, offset, value); | |
145 | } | |
146 | ||
147 | ||
148 | /* | |
149 | * cpqhp_set_irq | |
150 | * | |
151 | * @bus_num: bus number of PCI device | |
152 | * @dev_num: device number of PCI device | |
153 | * @slot: pointer to u8 where slot number will be returned | |
154 | */ | |
155 | int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) | |
156 | { | |
157 | int rc = 0; | |
158 | ||
159 | if (cpqhp_legacy_mode) { | |
160 | struct pci_dev *fakedev; | |
161 | struct pci_bus *fakebus; | |
162 | u16 temp_word; | |
163 | ||
164 | fakedev = kmalloc(sizeof(*fakedev), GFP_KERNEL); | |
165 | fakebus = kmalloc(sizeof(*fakebus), GFP_KERNEL); | |
166 | if (!fakedev || !fakebus) { | |
167 | kfree(fakedev); | |
168 | kfree(fakebus); | |
169 | return -ENOMEM; | |
170 | } | |
171 | ||
172 | fakedev->devfn = dev_num << 3; | |
173 | fakedev->bus = fakebus; | |
174 | fakebus->number = bus_num; | |
175 | dbg("%s: dev %d, bus %d, pin %d, num %d\n", | |
66bef8c0 | 176 | __func__, dev_num, bus_num, int_pin, irq_num); |
98d3333a | 177 | rc = pcibios_set_irq_routing(fakedev, int_pin - 1, irq_num); |
1da177e4 LT |
178 | kfree(fakedev); |
179 | kfree(fakebus); | |
66bef8c0 | 180 | dbg("%s: rc %d\n", __func__, rc); |
1da177e4 LT |
181 | if (!rc) |
182 | return !rc; | |
183 | ||
427438c6 | 184 | /* set the Edge Level Control Register (ELCR) */ |
1da177e4 LT |
185 | temp_word = inb(0x4d0); |
186 | temp_word |= inb(0x4d1) << 8; | |
187 | ||
188 | temp_word |= 0x01 << irq_num; | |
189 | ||
427438c6 AC |
190 | /* This should only be for x86 as it sets the Edge Level |
191 | * Control Register | |
192 | */ | |
193 | outb((u8) (temp_word & 0xFF), 0x4d0); outb((u8) ((temp_word & | |
194 | 0xFF00) >> 8), 0x4d1); rc = 0; } | |
1da177e4 LT |
195 | |
196 | return rc; | |
197 | } | |
198 | ||
199 | ||
1da177e4 LT |
200 | static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) |
201 | { | |
202 | u16 tdevice; | |
203 | u32 work; | |
204 | u8 tbus; | |
205 | ||
206 | ctrl->pci_bus->number = bus_num; | |
207 | ||
208 | for (tdevice = 0; tdevice < 0xFF; tdevice++) { | |
427438c6 | 209 | /* Scan for access first */ |
1da177e4 LT |
210 | if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) |
211 | continue; | |
212 | dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); | |
427438c6 | 213 | /* Yep we got one. Not a bridge ? */ |
1da177e4 LT |
214 | if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { |
215 | *dev_num = tdevice; | |
216 | dbg("found it !\n"); | |
217 | return 0; | |
218 | } | |
219 | } | |
220 | for (tdevice = 0; tdevice < 0xFF; tdevice++) { | |
427438c6 | 221 | /* Scan for access first */ |
1da177e4 LT |
222 | if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) |
223 | continue; | |
224 | dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); | |
427438c6 | 225 | /* Yep we got one. bridge ? */ |
1da177e4 LT |
226 | if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { |
227 | pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); | |
e3265ea3 | 228 | /* XXX: no recursion, wtf? */ |
1da177e4 | 229 | dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); |
e3265ea3 | 230 | return 0; |
1da177e4 LT |
231 | } |
232 | } | |
233 | ||
234 | return -1; | |
235 | } | |
236 | ||
237 | ||
238 | static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) | |
239 | { | |
b019ee67 | 240 | int loop, len; |
1da177e4 | 241 | u32 work; |
1da177e4 LT |
242 | u8 tbus, tdevice, tslot; |
243 | ||
b019ee67 | 244 | len = cpqhp_routing_table_length(); |
1da177e4 | 245 | for (loop = 0; loop < len; ++loop) { |
b019ee67 AC |
246 | tbus = cpqhp_routing_table->slots[loop].bus; |
247 | tdevice = cpqhp_routing_table->slots[loop].devfn; | |
248 | tslot = cpqhp_routing_table->slots[loop].slot; | |
1da177e4 LT |
249 | |
250 | if (tslot == slot) { | |
251 | *bus_num = tbus; | |
252 | *dev_num = tdevice; | |
253 | ctrl->pci_bus->number = tbus; | |
254 | pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); | |
b019ee67 | 255 | if (!nobridge || (work == 0xffffffff)) |
1da177e4 | 256 | return 0; |
1da177e4 LT |
257 | |
258 | dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); | |
259 | pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); | |
260 | dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); | |
261 | ||
262 | if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { | |
263 | pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus); | |
264 | dbg("Scan bus for Non Bridge: bus %d\n", tbus); | |
265 | if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { | |
266 | *bus_num = tbus; | |
1da177e4 LT |
267 | return 0; |
268 | } | |
b019ee67 | 269 | } else |
1da177e4 | 270 | return 0; |
1da177e4 LT |
271 | } |
272 | } | |
1da177e4 LT |
273 | return -1; |
274 | } | |
275 | ||
276 | ||
277 | int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) | |
278 | { | |
427438c6 AC |
279 | /* plain (bridges allowed) */ |
280 | return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); | |
1da177e4 LT |
281 | } |
282 | ||
283 | ||
427438c6 AC |
284 | /* More PCI configuration routines; this time centered around hotplug |
285 | * controller | |
286 | */ | |
1da177e4 LT |
287 | |
288 | ||
289 | /* | |
290 | * cpqhp_save_config | |
291 | * | |
292 | * Reads configuration for all slots in a PCI bus and saves info. | |
293 | * | |
294 | * Note: For non-hot plug busses, the slot # saved is the device # | |
295 | * | |
296 | * returns 0 if success | |
297 | */ | |
298 | int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) | |
299 | { | |
300 | long rc; | |
301 | u8 class_code; | |
302 | u8 header_type; | |
303 | u32 ID; | |
304 | u8 secondary_bus; | |
305 | struct pci_func *new_slot; | |
306 | int sub_bus; | |
307 | int FirstSupported; | |
308 | int LastSupported; | |
309 | int max_functions; | |
310 | int function; | |
311 | u8 DevError; | |
312 | int device = 0; | |
313 | int cloop = 0; | |
314 | int stop_it; | |
315 | int index; | |
316 | ||
427438c6 | 317 | /* Decide which slots are supported */ |
1da177e4 LT |
318 | |
319 | if (is_hot_plug) { | |
427438c6 AC |
320 | /* |
321 | * is_hot_plug is the slot mask | |
322 | */ | |
1da177e4 LT |
323 | FirstSupported = is_hot_plug >> 4; |
324 | LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; | |
325 | } else { | |
326 | FirstSupported = 0; | |
327 | LastSupported = 0x1F; | |
328 | } | |
329 | ||
427438c6 | 330 | /* Save PCI configuration space for all devices in supported slots */ |
1da177e4 LT |
331 | ctrl->pci_bus->number = busnumber; |
332 | for (device = FirstSupported; device <= LastSupported; device++) { | |
333 | ID = 0xFFFFFFFF; | |
1d2e8b1c | 334 | rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); |
1da177e4 | 335 | |
1d2e8b1c AC |
336 | if (ID == 0xFFFFFFFF) { |
337 | if (is_hot_plug) { | |
338 | /* Setup slot structure with entry for empty | |
339 | * slot | |
340 | */ | |
341 | new_slot = cpqhp_slot_create(busnumber); | |
342 | if (new_slot == NULL) | |
343 | return 1; | |
1da177e4 LT |
344 | |
345 | new_slot->bus = (u8) busnumber; | |
346 | new_slot->device = (u8) device; | |
1d2e8b1c AC |
347 | new_slot->function = 0; |
348 | new_slot->is_a_board = 0; | |
349 | new_slot->presence_save = 0; | |
350 | new_slot->switch_save = 0; | |
351 | } | |
352 | continue; | |
353 | } | |
354 | ||
355 | rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); | |
356 | if (rc) | |
357 | return rc; | |
358 | ||
359 | rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); | |
360 | if (rc) | |
361 | return rc; | |
362 | ||
363 | /* If multi-function device, set max_functions to 8 */ | |
364 | if (header_type & 0x80) | |
365 | max_functions = 8; | |
366 | else | |
367 | max_functions = 1; | |
368 | ||
369 | function = 0; | |
370 | ||
371 | do { | |
372 | DevError = 0; | |
373 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | |
374 | /* Recurse the subordinate bus | |
375 | * get the subordinate bus number | |
376 | */ | |
377 | rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); | |
378 | if (rc) { | |
379 | return rc; | |
380 | } else { | |
381 | sub_bus = (int) secondary_bus; | |
382 | ||
383 | /* Save secondary bus cfg spc | |
384 | * with this recursive call. | |
385 | */ | |
386 | rc = cpqhp_save_config(ctrl, sub_bus, 0); | |
1da177e4 LT |
387 | if (rc) |
388 | return rc; | |
1d2e8b1c | 389 | ctrl->pci_bus->number = busnumber; |
1da177e4 | 390 | } |
1d2e8b1c | 391 | } |
1da177e4 | 392 | |
1d2e8b1c AC |
393 | index = 0; |
394 | new_slot = cpqhp_slot_find(busnumber, device, index++); | |
395 | while (new_slot && | |
396 | (new_slot->function != (u8) function)) | |
397 | new_slot = cpqhp_slot_find(busnumber, device, index++); | |
1da177e4 | 398 | |
1d2e8b1c AC |
399 | if (!new_slot) { |
400 | /* Setup slot structure. */ | |
401 | new_slot = cpqhp_slot_create(busnumber); | |
402 | if (new_slot == NULL) | |
403 | return 1; | |
404 | } | |
1da177e4 | 405 | |
1d2e8b1c AC |
406 | new_slot->bus = (u8) busnumber; |
407 | new_slot->device = (u8) device; | |
408 | new_slot->function = (u8) function; | |
409 | new_slot->is_a_board = 1; | |
410 | new_slot->switch_save = 0x10; | |
411 | /* In case of unsupported board */ | |
412 | new_slot->status = DevError; | |
12a9da0f | 413 | new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); |
1d2e8b1c AC |
414 | |
415 | for (cloop = 0; cloop < 0x20; cloop++) { | |
416 | rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); | |
417 | if (rc) | |
418 | return rc; | |
419 | } | |
420 | ||
12a9da0f AC |
421 | pci_dev_put(new_slot->pci_dev); |
422 | ||
1d2e8b1c | 423 | function++; |
1da177e4 | 424 | |
1d2e8b1c AC |
425 | stop_it = 0; |
426 | ||
427 | /* this loop skips to the next present function | |
428 | * reading in Class Code and Header type. | |
429 | */ | |
430 | while ((function < max_functions) && (!stop_it)) { | |
431 | rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); | |
432 | if (ID == 0xFFFFFFFF) { | |
433 | function++; | |
434 | continue; | |
1da177e4 | 435 | } |
1d2e8b1c AC |
436 | rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); |
437 | if (rc) | |
438 | return rc; | |
1da177e4 | 439 | |
1d2e8b1c AC |
440 | rc = pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); |
441 | if (rc) | |
442 | return rc; | |
1da177e4 | 443 | |
1d2e8b1c | 444 | stop_it++; |
1da177e4 LT |
445 | } |
446 | ||
1d2e8b1c | 447 | } while (function < max_functions); |
427438c6 | 448 | } /* End of FOR loop */ |
1da177e4 | 449 | |
1d2e8b1c | 450 | return 0; |
1da177e4 LT |
451 | } |
452 | ||
453 | ||
454 | /* | |
455 | * cpqhp_save_slot_config | |
456 | * | |
457 | * Saves configuration info for all PCI devices in a given slot | |
458 | * including subordinate busses. | |
459 | * | |
460 | * returns 0 if success | |
461 | */ | |
462 | int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) | |
463 | { | |
464 | long rc; | |
465 | u8 class_code; | |
466 | u8 header_type; | |
467 | u32 ID; | |
468 | u8 secondary_bus; | |
469 | int sub_bus; | |
470 | int max_functions; | |
de86ae16 | 471 | int function = 0; |
1da177e4 LT |
472 | int cloop = 0; |
473 | int stop_it; | |
474 | ||
475 | ID = 0xFFFFFFFF; | |
476 | ||
477 | ctrl->pci_bus->number = new_slot->bus; | |
478 | pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); | |
479 | ||
de86ae16 AC |
480 | if (ID == 0xFFFFFFFF) |
481 | return 2; | |
1da177e4 | 482 | |
de86ae16 AC |
483 | pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); |
484 | pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); | |
1da177e4 | 485 | |
de86ae16 AC |
486 | if (header_type & 0x80) /* Multi-function device */ |
487 | max_functions = 8; | |
488 | else | |
489 | max_functions = 1; | |
1da177e4 | 490 | |
de86ae16 AC |
491 | while (function < max_functions) { |
492 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | |
493 | /* Recurse the subordinate bus */ | |
494 | pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); | |
1da177e4 | 495 | |
de86ae16 | 496 | sub_bus = (int) secondary_bus; |
1da177e4 | 497 | |
de86ae16 AC |
498 | /* Save the config headers for the secondary |
499 | * bus. | |
500 | */ | |
501 | rc = cpqhp_save_config(ctrl, sub_bus, 0); | |
502 | if (rc) | |
503 | return(rc); | |
504 | ctrl->pci_bus->number = new_slot->bus; | |
1da177e4 | 505 | |
de86ae16 | 506 | } |
1da177e4 | 507 | |
de86ae16 | 508 | new_slot->status = 0; |
1da177e4 | 509 | |
de86ae16 AC |
510 | for (cloop = 0; cloop < 0x20; cloop++) |
511 | pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); | |
1da177e4 | 512 | |
de86ae16 | 513 | function++; |
1da177e4 | 514 | |
de86ae16 | 515 | stop_it = 0; |
1da177e4 | 516 | |
de86ae16 AC |
517 | /* this loop skips to the next present function |
518 | * reading in the Class Code and the Header type. | |
519 | */ | |
520 | while ((function < max_functions) && (!stop_it)) { | |
521 | pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); | |
1da177e4 | 522 | |
de86ae16 AC |
523 | if (ID == 0xFFFFFFFF) |
524 | function++; | |
525 | else { | |
526 | pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); | |
527 | pci_bus_read_config_byte(ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); | |
528 | stop_it++; | |
1da177e4 | 529 | } |
de86ae16 | 530 | } |
1da177e4 | 531 | |
1da177e4 LT |
532 | } |
533 | ||
534 | return 0; | |
535 | } | |
536 | ||
537 | ||
538 | /* | |
539 | * cpqhp_save_base_addr_length | |
540 | * | |
541 | * Saves the length of all base address registers for the | |
542 | * specified slot. this is for hot plug REPLACE | |
543 | * | |
544 | * returns 0 if success | |
545 | */ | |
546 | int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) | |
547 | { | |
548 | u8 cloop; | |
549 | u8 header_type; | |
550 | u8 secondary_bus; | |
551 | u8 type; | |
552 | int sub_bus; | |
553 | u32 temp_register; | |
554 | u32 base; | |
555 | u32 rc; | |
556 | struct pci_func *next; | |
557 | int index = 0; | |
558 | struct pci_bus *pci_bus = ctrl->pci_bus; | |
559 | unsigned int devfn; | |
560 | ||
561 | func = cpqhp_slot_find(func->bus, func->device, index++); | |
562 | ||
563 | while (func != NULL) { | |
564 | pci_bus->number = func->bus; | |
565 | devfn = PCI_DEVFN(func->device, func->function); | |
566 | ||
427438c6 | 567 | /* Check for Bridge */ |
1da177e4 LT |
568 | pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); |
569 | ||
570 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | |
1da177e4 LT |
571 | pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); |
572 | ||
573 | sub_bus = (int) secondary_bus; | |
574 | ||
575 | next = cpqhp_slot_list[sub_bus]; | |
576 | ||
577 | while (next != NULL) { | |
578 | rc = cpqhp_save_base_addr_length(ctrl, next); | |
579 | if (rc) | |
580 | return rc; | |
581 | ||
582 | next = next->next; | |
583 | } | |
584 | pci_bus->number = func->bus; | |
585 | ||
427438c6 AC |
586 | /* FIXME: this loop is duplicated in the non-bridge |
587 | * case. The two could be rolled together Figure out | |
588 | * IO and memory base lengths | |
589 | */ | |
1da177e4 LT |
590 | for (cloop = 0x10; cloop <= 0x14; cloop += 4) { |
591 | temp_register = 0xFFFFFFFF; | |
592 | pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); | |
593 | pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); | |
427438c6 AC |
594 | /* If this register is implemented */ |
595 | if (base) { | |
1da177e4 | 596 | if (base & 0x01L) { |
427438c6 AC |
597 | /* IO base |
598 | * set base = amount of IO space | |
599 | * requested | |
600 | */ | |
1da177e4 LT |
601 | base = base & 0xFFFFFFFE; |
602 | base = (~base) + 1; | |
603 | ||
604 | type = 1; | |
605 | } else { | |
427438c6 | 606 | /* memory base */ |
1da177e4 LT |
607 | base = base & 0xFFFFFFF0; |
608 | base = (~base) + 1; | |
609 | ||
610 | type = 0; | |
611 | } | |
612 | } else { | |
613 | base = 0x0L; | |
614 | type = 0; | |
615 | } | |
616 | ||
427438c6 | 617 | /* Save information in slot structure */ |
1da177e4 LT |
618 | func->base_length[(cloop - 0x10) >> 2] = |
619 | base; | |
620 | func->base_type[(cloop - 0x10) >> 2] = type; | |
621 | ||
427438c6 | 622 | } /* End of base register loop */ |
1da177e4 | 623 | |
427438c6 AC |
624 | } else if ((header_type & 0x7F) == 0x00) { |
625 | /* Figure out IO and memory base lengths */ | |
1da177e4 LT |
626 | for (cloop = 0x10; cloop <= 0x24; cloop += 4) { |
627 | temp_register = 0xFFFFFFFF; | |
628 | pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); | |
629 | pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); | |
630 | ||
427438c6 AC |
631 | /* If this register is implemented */ |
632 | if (base) { | |
1da177e4 | 633 | if (base & 0x01L) { |
427438c6 AC |
634 | /* IO base |
635 | * base = amount of IO space | |
636 | * requested | |
637 | */ | |
1da177e4 LT |
638 | base = base & 0xFFFFFFFE; |
639 | base = (~base) + 1; | |
640 | ||
641 | type = 1; | |
642 | } else { | |
427438c6 AC |
643 | /* memory base |
644 | * base = amount of memory | |
645 | * space requested | |
646 | */ | |
1da177e4 LT |
647 | base = base & 0xFFFFFFF0; |
648 | base = (~base) + 1; | |
649 | ||
650 | type = 0; | |
651 | } | |
652 | } else { | |
653 | base = 0x0L; | |
654 | type = 0; | |
655 | } | |
656 | ||
427438c6 | 657 | /* Save information in slot structure */ |
1da177e4 LT |
658 | func->base_length[(cloop - 0x10) >> 2] = base; |
659 | func->base_type[(cloop - 0x10) >> 2] = type; | |
660 | ||
427438c6 | 661 | } /* End of base register loop */ |
1da177e4 | 662 | |
427438c6 | 663 | } else { /* Some other unknown header type */ |
1da177e4 LT |
664 | } |
665 | ||
427438c6 | 666 | /* find the next device in this slot */ |
1da177e4 LT |
667 | func = cpqhp_slot_find(func->bus, func->device, index++); |
668 | } | |
669 | ||
670 | return(0); | |
671 | } | |
672 | ||
673 | ||
674 | /* | |
675 | * cpqhp_save_used_resources | |
676 | * | |
677 | * Stores used resource information for existing boards. this is | |
678 | * for boards that were in the system when this driver was loaded. | |
679 | * this function is for hot plug ADD | |
680 | * | |
681 | * returns 0 if success | |
682 | */ | |
683 | int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) | |
684 | { | |
685 | u8 cloop; | |
686 | u8 header_type; | |
687 | u8 secondary_bus; | |
688 | u8 temp_byte; | |
689 | u8 b_base; | |
690 | u8 b_length; | |
691 | u16 command; | |
692 | u16 save_command; | |
693 | u16 w_base; | |
694 | u16 w_length; | |
695 | u32 temp_register; | |
696 | u32 save_base; | |
697 | u32 base; | |
698 | int index = 0; | |
699 | struct pci_resource *mem_node; | |
700 | struct pci_resource *p_mem_node; | |
701 | struct pci_resource *io_node; | |
702 | struct pci_resource *bus_node; | |
703 | struct pci_bus *pci_bus = ctrl->pci_bus; | |
704 | unsigned int devfn; | |
705 | ||
706 | func = cpqhp_slot_find(func->bus, func->device, index++); | |
707 | ||
708 | while ((func != NULL) && func->is_a_board) { | |
709 | pci_bus->number = func->bus; | |
710 | devfn = PCI_DEVFN(func->device, func->function); | |
711 | ||
427438c6 | 712 | /* Save the command register */ |
1da177e4 LT |
713 | pci_bus_read_config_word(pci_bus, devfn, PCI_COMMAND, &save_command); |
714 | ||
427438c6 | 715 | /* disable card */ |
1da177e4 LT |
716 | command = 0x00; |
717 | pci_bus_write_config_word(pci_bus, devfn, PCI_COMMAND, command); | |
718 | ||
427438c6 | 719 | /* Check for Bridge */ |
1da177e4 LT |
720 | pci_bus_read_config_byte(pci_bus, devfn, PCI_HEADER_TYPE, &header_type); |
721 | ||
427438c6 AC |
722 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { |
723 | /* Clear Bridge Control Register */ | |
1da177e4 LT |
724 | command = 0x00; |
725 | pci_bus_write_config_word(pci_bus, devfn, PCI_BRIDGE_CONTROL, command); | |
726 | pci_bus_read_config_byte(pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); | |
727 | pci_bus_read_config_byte(pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); | |
728 | ||
729 | bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); | |
730 | if (!bus_node) | |
731 | return -ENOMEM; | |
732 | ||
733 | bus_node->base = secondary_bus; | |
734 | bus_node->length = temp_byte - secondary_bus + 1; | |
735 | ||
736 | bus_node->next = func->bus_head; | |
737 | func->bus_head = bus_node; | |
738 | ||
427438c6 | 739 | /* Save IO base and Limit registers */ |
1da177e4 LT |
740 | pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_BASE, &b_base); |
741 | pci_bus_read_config_byte(pci_bus, devfn, PCI_IO_LIMIT, &b_length); | |
742 | ||
743 | if ((b_base <= b_length) && (save_command & 0x01)) { | |
744 | io_node = kmalloc(sizeof(*io_node), GFP_KERNEL); | |
745 | if (!io_node) | |
746 | return -ENOMEM; | |
747 | ||
748 | io_node->base = (b_base & 0xF0) << 8; | |
749 | io_node->length = (b_length - b_base + 0x10) << 8; | |
750 | ||
751 | io_node->next = func->io_head; | |
752 | func->io_head = io_node; | |
753 | } | |
754 | ||
427438c6 | 755 | /* Save memory base and Limit registers */ |
1da177e4 LT |
756 | pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_BASE, &w_base); |
757 | pci_bus_read_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); | |
758 | ||
759 | if ((w_base <= w_length) && (save_command & 0x02)) { | |
760 | mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); | |
761 | if (!mem_node) | |
762 | return -ENOMEM; | |
763 | ||
764 | mem_node->base = w_base << 16; | |
765 | mem_node->length = (w_length - w_base + 0x10) << 16; | |
766 | ||
767 | mem_node->next = func->mem_head; | |
768 | func->mem_head = mem_node; | |
769 | } | |
770 | ||
427438c6 | 771 | /* Save prefetchable memory base and Limit registers */ |
1da177e4 LT |
772 | pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); |
773 | pci_bus_read_config_word(pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); | |
774 | ||
775 | if ((w_base <= w_length) && (save_command & 0x02)) { | |
776 | p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); | |
777 | if (!p_mem_node) | |
778 | return -ENOMEM; | |
779 | ||
780 | p_mem_node->base = w_base << 16; | |
781 | p_mem_node->length = (w_length - w_base + 0x10) << 16; | |
782 | ||
783 | p_mem_node->next = func->p_mem_head; | |
784 | func->p_mem_head = p_mem_node; | |
785 | } | |
427438c6 | 786 | /* Figure out IO and memory base lengths */ |
1da177e4 LT |
787 | for (cloop = 0x10; cloop <= 0x14; cloop += 4) { |
788 | pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); | |
789 | ||
790 | temp_register = 0xFFFFFFFF; | |
791 | pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); | |
792 | pci_bus_read_config_dword(pci_bus, devfn, cloop, &base); | |
793 | ||
794 | temp_register = base; | |
795 | ||
427438c6 AC |
796 | /* If this register is implemented */ |
797 | if (base) { | |
1da177e4 LT |
798 | if (((base & 0x03L) == 0x01) |
799 | && (save_command & 0x01)) { | |
427438c6 AC |
800 | /* IO base |
801 | * set temp_register = amount | |
802 | * of IO space requested | |
803 | */ | |
1da177e4 LT |
804 | temp_register = base & 0xFFFFFFFE; |
805 | temp_register = (~temp_register) + 1; | |
806 | ||
807 | io_node = kmalloc(sizeof(*io_node), | |
808 | GFP_KERNEL); | |
809 | if (!io_node) | |
810 | return -ENOMEM; | |
811 | ||
812 | io_node->base = | |
813 | save_base & (~0x03L); | |
814 | io_node->length = temp_register; | |
815 | ||
816 | io_node->next = func->io_head; | |
817 | func->io_head = io_node; | |
818 | } else | |
819 | if (((base & 0x0BL) == 0x08) | |
820 | && (save_command & 0x02)) { | |
427438c6 | 821 | /* prefetchable memory base */ |
1da177e4 LT |
822 | temp_register = base & 0xFFFFFFF0; |
823 | temp_register = (~temp_register) + 1; | |
824 | ||
825 | p_mem_node = kmalloc(sizeof(*p_mem_node), | |
826 | GFP_KERNEL); | |
827 | if (!p_mem_node) | |
828 | return -ENOMEM; | |
829 | ||
830 | p_mem_node->base = save_base & (~0x0FL); | |
831 | p_mem_node->length = temp_register; | |
832 | ||
833 | p_mem_node->next = func->p_mem_head; | |
834 | func->p_mem_head = p_mem_node; | |
835 | } else | |
836 | if (((base & 0x0BL) == 0x00) | |
837 | && (save_command & 0x02)) { | |
427438c6 | 838 | /* prefetchable memory base */ |
1da177e4 LT |
839 | temp_register = base & 0xFFFFFFF0; |
840 | temp_register = (~temp_register) + 1; | |
841 | ||
842 | mem_node = kmalloc(sizeof(*mem_node), | |
843 | GFP_KERNEL); | |
844 | if (!mem_node) | |
845 | return -ENOMEM; | |
846 | ||
847 | mem_node->base = save_base & (~0x0FL); | |
848 | mem_node->length = temp_register; | |
849 | ||
850 | mem_node->next = func->mem_head; | |
851 | func->mem_head = mem_node; | |
852 | } else | |
853 | return(1); | |
854 | } | |
427438c6 AC |
855 | } /* End of base register loop */ |
856 | /* Standard header */ | |
857 | } else if ((header_type & 0x7F) == 0x00) { | |
858 | /* Figure out IO and memory base lengths */ | |
1da177e4 LT |
859 | for (cloop = 0x10; cloop <= 0x24; cloop += 4) { |
860 | pci_bus_read_config_dword(pci_bus, devfn, cloop, &save_base); | |
861 | ||
862 | temp_register = 0xFFFFFFFF; | |
863 | pci_bus_write_config_dword(pci_bus, devfn, cloop, temp_register); | |
864 | pci_bus_read_config_dword(pci_bus, devfn, cloop, &base); | |
865 | ||
866 | temp_register = base; | |
867 | ||
427438c6 AC |
868 | /* If this register is implemented */ |
869 | if (base) { | |
1da177e4 LT |
870 | if (((base & 0x03L) == 0x01) |
871 | && (save_command & 0x01)) { | |
427438c6 AC |
872 | /* IO base |
873 | * set temp_register = amount | |
874 | * of IO space requested | |
875 | */ | |
1da177e4 LT |
876 | temp_register = base & 0xFFFFFFFE; |
877 | temp_register = (~temp_register) + 1; | |
878 | ||
879 | io_node = kmalloc(sizeof(*io_node), | |
880 | GFP_KERNEL); | |
881 | if (!io_node) | |
882 | return -ENOMEM; | |
883 | ||
884 | io_node->base = save_base & (~0x01L); | |
885 | io_node->length = temp_register; | |
886 | ||
887 | io_node->next = func->io_head; | |
888 | func->io_head = io_node; | |
889 | } else | |
890 | if (((base & 0x0BL) == 0x08) | |
891 | && (save_command & 0x02)) { | |
427438c6 | 892 | /* prefetchable memory base */ |
1da177e4 LT |
893 | temp_register = base & 0xFFFFFFF0; |
894 | temp_register = (~temp_register) + 1; | |
895 | ||
896 | p_mem_node = kmalloc(sizeof(*p_mem_node), | |
897 | GFP_KERNEL); | |
898 | if (!p_mem_node) | |
899 | return -ENOMEM; | |
900 | ||
901 | p_mem_node->base = save_base & (~0x0FL); | |
902 | p_mem_node->length = temp_register; | |
903 | ||
904 | p_mem_node->next = func->p_mem_head; | |
905 | func->p_mem_head = p_mem_node; | |
906 | } else | |
907 | if (((base & 0x0BL) == 0x00) | |
908 | && (save_command & 0x02)) { | |
427438c6 | 909 | /* prefetchable memory base */ |
1da177e4 LT |
910 | temp_register = base & 0xFFFFFFF0; |
911 | temp_register = (~temp_register) + 1; | |
912 | ||
913 | mem_node = kmalloc(sizeof(*mem_node), | |
914 | GFP_KERNEL); | |
915 | if (!mem_node) | |
916 | return -ENOMEM; | |
917 | ||
918 | mem_node->base = save_base & (~0x0FL); | |
919 | mem_node->length = temp_register; | |
920 | ||
921 | mem_node->next = func->mem_head; | |
922 | func->mem_head = mem_node; | |
923 | } else | |
924 | return(1); | |
925 | } | |
427438c6 | 926 | } /* End of base register loop */ |
1da177e4 LT |
927 | } |
928 | ||
427438c6 | 929 | /* find the next device in this slot */ |
1da177e4 LT |
930 | func = cpqhp_slot_find(func->bus, func->device, index++); |
931 | } | |
932 | ||
4aabb58e | 933 | return 0; |
1da177e4 LT |
934 | } |
935 | ||
936 | ||
937 | /* | |
938 | * cpqhp_configure_board | |
939 | * | |
940 | * Copies saved configuration information to one slot. | |
941 | * this is called recursively for bridge devices. | |
942 | * this is for hot plug REPLACE! | |
943 | * | |
944 | * returns 0 if success | |
945 | */ | |
946 | int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) | |
947 | { | |
948 | int cloop; | |
949 | u8 header_type; | |
950 | u8 secondary_bus; | |
951 | int sub_bus; | |
952 | struct pci_func *next; | |
953 | u32 temp; | |
954 | u32 rc; | |
955 | int index = 0; | |
956 | struct pci_bus *pci_bus = ctrl->pci_bus; | |
957 | unsigned int devfn; | |
958 | ||
959 | func = cpqhp_slot_find(func->bus, func->device, index++); | |
960 | ||
961 | while (func != NULL) { | |
962 | pci_bus->number = func->bus; | |
963 | devfn = PCI_DEVFN(func->device, func->function); | |
964 | ||
427438c6 AC |
965 | /* Start at the top of config space so that the control |
966 | * registers are programmed last | |
967 | */ | |
4aabb58e | 968 | for (cloop = 0x3C; cloop > 0; cloop -= 4) |
1da177e4 | 969 | pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); |
1da177e4 LT |
970 | |
971 | pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); | |
972 | ||
427438c6 AC |
973 | /* If this is a bridge device, restore subordinate devices */ |
974 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { | |
1da177e4 LT |
975 | pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); |
976 | ||
977 | sub_bus = (int) secondary_bus; | |
978 | ||
979 | next = cpqhp_slot_list[sub_bus]; | |
980 | ||
981 | while (next != NULL) { | |
982 | rc = cpqhp_configure_board(ctrl, next); | |
983 | if (rc) | |
984 | return rc; | |
985 | ||
986 | next = next->next; | |
987 | } | |
988 | } else { | |
989 | ||
427438c6 AC |
990 | /* Check all the base Address Registers to make sure |
991 | * they are the same. If not, the board is different. | |
992 | */ | |
1da177e4 LT |
993 | |
994 | for (cloop = 16; cloop < 40; cloop += 4) { | |
995 | pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); | |
996 | ||
997 | if (temp != func->config_space[cloop >> 2]) { | |
998 | dbg("Config space compare failure!!! offset = %x\n", cloop); | |
999 | dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); | |
1000 | dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]); | |
1001 | return 1; | |
1002 | } | |
1003 | } | |
1004 | } | |
1005 | ||
1006 | func->configured = 1; | |
1007 | ||
1008 | func = cpqhp_slot_find(func->bus, func->device, index++); | |
1009 | } | |
1010 | ||
1011 | return 0; | |
1012 | } | |
1013 | ||
1014 | ||
1015 | /* | |
1016 | * cpqhp_valid_replace | |
1017 | * | |
1018 | * this function checks to see if a board is the same as the | |
1019 | * one it is replacing. this check will detect if the device's | |
1020 | * vendor or device id's are the same | |
1021 | * | |
1022 | * returns 0 if the board is the same nonzero otherwise | |
1023 | */ | |
1024 | int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) | |
1025 | { | |
1026 | u8 cloop; | |
1027 | u8 header_type; | |
1028 | u8 secondary_bus; | |
1029 | u8 type; | |
1030 | u32 temp_register = 0; | |
1031 | u32 base; | |
1032 | u32 rc; | |
1033 | struct pci_func *next; | |
1034 | int index = 0; | |
1035 | struct pci_bus *pci_bus = ctrl->pci_bus; | |
1036 | unsigned int devfn; | |
1037 | ||
1038 | if (!func->is_a_board) | |
1039 | return(ADD_NOT_SUPPORTED); | |
1040 | ||
1041 | func = cpqhp_slot_find(func->bus, func->device, index++); | |
1042 | ||
1043 | while (func != NULL) { | |
1044 | pci_bus->number = func->bus; | |
1045 | devfn = PCI_DEVFN(func->device, func->function); | |
1046 | ||
1047 | pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); | |
1048 | ||
427438c6 | 1049 | /* No adapter present */ |
1da177e4 LT |
1050 | if (temp_register == 0xFFFFFFFF) |
1051 | return(NO_ADAPTER_PRESENT); | |
1052 | ||
1053 | if (temp_register != func->config_space[0]) | |
1054 | return(ADAPTER_NOT_SAME); | |
1055 | ||
427438c6 | 1056 | /* Check for same revision number and class code */ |
1da177e4 LT |
1057 | pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); |
1058 | ||
427438c6 | 1059 | /* Adapter not the same */ |
1da177e4 LT |
1060 | if (temp_register != func->config_space[0x08 >> 2]) |
1061 | return(ADAPTER_NOT_SAME); | |
1062 | ||
427438c6 | 1063 | /* Check for Bridge */ |
1da177e4 LT |
1064 | pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); |
1065 | ||
427438c6 AC |
1066 | if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { |
1067 | /* In order to continue checking, we must program the | |
1068 | * bus registers in the bridge to respond to accesses | |
1069 | * for its subordinate bus(es) | |
1070 | */ | |
1da177e4 LT |
1071 | |
1072 | temp_register = func->config_space[0x18 >> 2]; | |
1073 | pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); | |
1074 | ||
1075 | secondary_bus = (temp_register >> 8) & 0xFF; | |
1076 | ||
1077 | next = cpqhp_slot_list[secondary_bus]; | |
1078 | ||
1079 | while (next != NULL) { | |
1080 | rc = cpqhp_valid_replace(ctrl, next); | |
1081 | if (rc) | |
1082 | return rc; | |
1083 | ||
1084 | next = next->next; | |
1085 | } | |
1086 | ||
1087 | } | |
427438c6 | 1088 | /* Check to see if it is a standard config header */ |
1da177e4 | 1089 | else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { |
427438c6 | 1090 | /* Check subsystem vendor and ID */ |
1da177e4 LT |
1091 | pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); |
1092 | ||
1093 | if (temp_register != func->config_space[0x2C >> 2]) { | |
427438c6 AC |
1094 | /* If it's a SMART-2 and the register isn't |
1095 | * filled in, ignore the difference because | |
1096 | * they just have an old rev of the firmware | |
1097 | */ | |
1da177e4 LT |
1098 | if (!((func->config_space[0] == 0xAE100E11) |
1099 | && (temp_register == 0x00L))) | |
1100 | return(ADAPTER_NOT_SAME); | |
1101 | } | |
427438c6 | 1102 | /* Figure out IO and memory base lengths */ |
1da177e4 LT |
1103 | for (cloop = 0x10; cloop <= 0x24; cloop += 4) { |
1104 | temp_register = 0xFFFFFFFF; | |
1105 | pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); | |
1106 | pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); | |
427438c6 AC |
1107 | |
1108 | /* If this register is implemented */ | |
1109 | if (base) { | |
1da177e4 | 1110 | if (base & 0x01L) { |
427438c6 AC |
1111 | /* IO base |
1112 | * set base = amount of IO | |
1113 | * space requested | |
1114 | */ | |
1da177e4 LT |
1115 | base = base & 0xFFFFFFFE; |
1116 | base = (~base) + 1; | |
1117 | ||
1118 | type = 1; | |
1119 | } else { | |
427438c6 | 1120 | /* memory base */ |
1da177e4 LT |
1121 | base = base & 0xFFFFFFF0; |
1122 | base = (~base) + 1; | |
1123 | ||
1124 | type = 0; | |
1125 | } | |
1126 | } else { | |
1127 | base = 0x0L; | |
1128 | type = 0; | |
1129 | } | |
1130 | ||
427438c6 | 1131 | /* Check information in slot structure */ |
1da177e4 LT |
1132 | if (func->base_length[(cloop - 0x10) >> 2] != base) |
1133 | return(ADAPTER_NOT_SAME); | |
1134 | ||
1135 | if (func->base_type[(cloop - 0x10) >> 2] != type) | |
1136 | return(ADAPTER_NOT_SAME); | |
1137 | ||
427438c6 | 1138 | } /* End of base register loop */ |
1da177e4 | 1139 | |
427438c6 | 1140 | } /* End of (type 0 config space) else */ |
1da177e4 | 1141 | else { |
427438c6 AC |
1142 | /* this is not a type 0 or 1 config space header so |
1143 | * we don't know how to do it | |
1144 | */ | |
1da177e4 LT |
1145 | return(DEVICE_TYPE_NOT_SUPPORTED); |
1146 | } | |
1147 | ||
427438c6 | 1148 | /* Get the next function */ |
1da177e4 LT |
1149 | func = cpqhp_slot_find(func->bus, func->device, index++); |
1150 | } | |
1151 | ||
1152 | ||
1153 | return 0; | |
1154 | } | |
1155 | ||
1156 | ||
1157 | /* | |
1158 | * cpqhp_find_available_resources | |
1159 | * | |
1160 | * Finds available memory, IO, and IRQ resources for programming | |
1161 | * devices which may be added to the system | |
1162 | * this function is for hot plug ADD! | |
1163 | * | |
1164 | * returns 0 if success | |
861fefbf | 1165 | */ |
1da177e4 LT |
1166 | int cpqhp_find_available_resources(struct controller *ctrl, void __iomem *rom_start) |
1167 | { | |
1168 | u8 temp; | |
1169 | u8 populated_slot; | |
1170 | u8 bridged_slot; | |
1171 | void __iomem *one_slot; | |
1172 | void __iomem *rom_resource_table; | |
1173 | struct pci_func *func = NULL; | |
1174 | int i = 10, index; | |
1175 | u32 temp_dword, rc; | |
1176 | struct pci_resource *mem_node; | |
1177 | struct pci_resource *p_mem_node; | |
1178 | struct pci_resource *io_node; | |
1179 | struct pci_resource *bus_node; | |
1180 | ||
1181 | rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); | |
1182 | dbg("rom_resource_table = %p\n", rom_resource_table); | |
1183 | ||
4aabb58e | 1184 | if (rom_resource_table == NULL) |
1da177e4 | 1185 | return -ENODEV; |
4aabb58e | 1186 | |
427438c6 | 1187 | /* Sum all resources and setup resource maps */ |
1da177e4 LT |
1188 | unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); |
1189 | dbg("unused_IRQ = %x\n", unused_IRQ); | |
1190 | ||
1191 | temp = 0; | |
1192 | while (unused_IRQ) { | |
1193 | if (unused_IRQ & 1) { | |
1194 | cpqhp_disk_irq = temp; | |
1195 | break; | |
1196 | } | |
1197 | unused_IRQ = unused_IRQ >> 1; | |
1198 | temp++; | |
1199 | } | |
1200 | ||
1201 | dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); | |
1202 | unused_IRQ = unused_IRQ >> 1; | |
1203 | temp++; | |
1204 | ||
1205 | while (unused_IRQ) { | |
1206 | if (unused_IRQ & 1) { | |
1207 | cpqhp_nic_irq = temp; | |
1208 | break; | |
1209 | } | |
1210 | unused_IRQ = unused_IRQ >> 1; | |
1211 | temp++; | |
1212 | } | |
1213 | ||
1214 | dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); | |
1215 | unused_IRQ = readl(rom_resource_table + PCIIRQ); | |
1216 | ||
1217 | temp = 0; | |
1218 | ||
4aabb58e | 1219 | if (!cpqhp_nic_irq) |
1da177e4 | 1220 | cpqhp_nic_irq = ctrl->cfgspc_irq; |
1da177e4 | 1221 | |
4aabb58e | 1222 | if (!cpqhp_disk_irq) |
1da177e4 | 1223 | cpqhp_disk_irq = ctrl->cfgspc_irq; |
1da177e4 LT |
1224 | |
1225 | dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); | |
1226 | ||
1227 | rc = compaq_nvram_load(rom_start, ctrl); | |
1228 | if (rc) | |
1229 | return rc; | |
1230 | ||
1231 | one_slot = rom_resource_table + sizeof (struct hrt); | |
1232 | ||
1233 | i = readb(rom_resource_table + NUMBER_OF_ENTRIES); | |
1234 | dbg("number_of_entries = %d\n", i); | |
1235 | ||
1236 | if (!readb(one_slot + SECONDARY_BUS)) | |
1237 | return 1; | |
1238 | ||
1239 | dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); | |
1240 | ||
1241 | while (i && readb(one_slot + SECONDARY_BUS)) { | |
1242 | u8 dev_func = readb(one_slot + DEV_FUNC); | |
1243 | u8 primary_bus = readb(one_slot + PRIMARY_BUS); | |
1244 | u8 secondary_bus = readb(one_slot + SECONDARY_BUS); | |
1245 | u8 max_bus = readb(one_slot + MAX_BUS); | |
1246 | u16 io_base = readw(one_slot + IO_BASE); | |
1247 | u16 io_length = readw(one_slot + IO_LENGTH); | |
1248 | u16 mem_base = readw(one_slot + MEM_BASE); | |
1249 | u16 mem_length = readw(one_slot + MEM_LENGTH); | |
1250 | u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); | |
1251 | u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); | |
1252 | ||
1253 | dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", | |
1254 | dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, | |
1255 | primary_bus, secondary_bus, max_bus); | |
1256 | ||
427438c6 | 1257 | /* If this entry isn't for our controller's bus, ignore it */ |
1da177e4 LT |
1258 | if (primary_bus != ctrl->bus) { |
1259 | i--; | |
1260 | one_slot += sizeof (struct slot_rt); | |
1261 | continue; | |
1262 | } | |
427438c6 | 1263 | /* find out if this entry is for an occupied slot */ |
1da177e4 LT |
1264 | ctrl->pci_bus->number = primary_bus; |
1265 | pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); | |
1266 | dbg("temp_D_word = %x\n", temp_dword); | |
1267 | ||
1268 | if (temp_dword != 0xFFFFFFFF) { | |
1269 | index = 0; | |
1270 | func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); | |
1271 | ||
1272 | while (func && (func->function != (dev_func & 0x07))) { | |
1273 | dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); | |
1274 | func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); | |
1275 | } | |
1276 | ||
427438c6 | 1277 | /* If we can't find a match, skip this table entry */ |
1da177e4 LT |
1278 | if (!func) { |
1279 | i--; | |
1280 | one_slot += sizeof (struct slot_rt); | |
1281 | continue; | |
1282 | } | |
427438c6 | 1283 | /* this may not work and shouldn't be used */ |
1da177e4 LT |
1284 | if (secondary_bus != primary_bus) |
1285 | bridged_slot = 1; | |
1286 | else | |
1287 | bridged_slot = 0; | |
1288 | ||
1289 | populated_slot = 1; | |
1290 | } else { | |
1291 | populated_slot = 0; | |
1292 | bridged_slot = 0; | |
1293 | } | |
1294 | ||
1295 | ||
427438c6 | 1296 | /* If we've got a valid IO base, use it */ |
1da177e4 LT |
1297 | |
1298 | temp_dword = io_base + io_length; | |
1299 | ||
1300 | if ((io_base) && (temp_dword < 0x10000)) { | |
1301 | io_node = kmalloc(sizeof(*io_node), GFP_KERNEL); | |
1302 | if (!io_node) | |
1303 | return -ENOMEM; | |
1304 | ||
1305 | io_node->base = io_base; | |
1306 | io_node->length = io_length; | |
1307 | ||
1308 | dbg("found io_node(base, length) = %x, %x\n", | |
1309 | io_node->base, io_node->length); | |
1310 | dbg("populated slot =%d \n", populated_slot); | |
1311 | if (!populated_slot) { | |
1312 | io_node->next = ctrl->io_head; | |
1313 | ctrl->io_head = io_node; | |
1314 | } else { | |
1315 | io_node->next = func->io_head; | |
1316 | func->io_head = io_node; | |
1317 | } | |
1318 | } | |
1319 | ||
427438c6 | 1320 | /* If we've got a valid memory base, use it */ |
1da177e4 LT |
1321 | temp_dword = mem_base + mem_length; |
1322 | if ((mem_base) && (temp_dword < 0x10000)) { | |
1323 | mem_node = kmalloc(sizeof(*mem_node), GFP_KERNEL); | |
1324 | if (!mem_node) | |
1325 | return -ENOMEM; | |
1326 | ||
1327 | mem_node->base = mem_base << 16; | |
1328 | ||
1329 | mem_node->length = mem_length << 16; | |
1330 | ||
1331 | dbg("found mem_node(base, length) = %x, %x\n", | |
1332 | mem_node->base, mem_node->length); | |
1333 | dbg("populated slot =%d \n", populated_slot); | |
1334 | if (!populated_slot) { | |
1335 | mem_node->next = ctrl->mem_head; | |
1336 | ctrl->mem_head = mem_node; | |
1337 | } else { | |
1338 | mem_node->next = func->mem_head; | |
1339 | func->mem_head = mem_node; | |
1340 | } | |
1341 | } | |
1342 | ||
427438c6 AC |
1343 | /* If we've got a valid prefetchable memory base, and |
1344 | * the base + length isn't greater than 0xFFFF | |
1345 | */ | |
1da177e4 LT |
1346 | temp_dword = pre_mem_base + pre_mem_length; |
1347 | if ((pre_mem_base) && (temp_dword < 0x10000)) { | |
1348 | p_mem_node = kmalloc(sizeof(*p_mem_node), GFP_KERNEL); | |
1349 | if (!p_mem_node) | |
1350 | return -ENOMEM; | |
1351 | ||
1352 | p_mem_node->base = pre_mem_base << 16; | |
1353 | ||
1354 | p_mem_node->length = pre_mem_length << 16; | |
1355 | dbg("found p_mem_node(base, length) = %x, %x\n", | |
1356 | p_mem_node->base, p_mem_node->length); | |
1357 | dbg("populated slot =%d \n", populated_slot); | |
1358 | ||
1359 | if (!populated_slot) { | |
1360 | p_mem_node->next = ctrl->p_mem_head; | |
1361 | ctrl->p_mem_head = p_mem_node; | |
1362 | } else { | |
1363 | p_mem_node->next = func->p_mem_head; | |
1364 | func->p_mem_head = p_mem_node; | |
1365 | } | |
1366 | } | |
1367 | ||
427438c6 AC |
1368 | /* If we've got a valid bus number, use it |
1369 | * The second condition is to ignore bus numbers on | |
1370 | * populated slots that don't have PCI-PCI bridges | |
1371 | */ | |
1da177e4 LT |
1372 | if (secondary_bus && (secondary_bus != primary_bus)) { |
1373 | bus_node = kmalloc(sizeof(*bus_node), GFP_KERNEL); | |
1374 | if (!bus_node) | |
1375 | return -ENOMEM; | |
1376 | ||
1377 | bus_node->base = secondary_bus; | |
1378 | bus_node->length = max_bus - secondary_bus + 1; | |
1379 | dbg("found bus_node(base, length) = %x, %x\n", | |
1380 | bus_node->base, bus_node->length); | |
1381 | dbg("populated slot =%d \n", populated_slot); | |
1382 | if (!populated_slot) { | |
1383 | bus_node->next = ctrl->bus_head; | |
1384 | ctrl->bus_head = bus_node; | |
1385 | } else { | |
1386 | bus_node->next = func->bus_head; | |
1387 | func->bus_head = bus_node; | |
1388 | } | |
1389 | } | |
1390 | ||
1391 | i--; | |
1392 | one_slot += sizeof (struct slot_rt); | |
1393 | } | |
1394 | ||
427438c6 AC |
1395 | /* If all of the following fail, we don't have any resources for |
1396 | * hot plug add | |
1397 | */ | |
1da177e4 LT |
1398 | rc = 1; |
1399 | rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); | |
1400 | rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); | |
1401 | rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); | |
1402 | rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); | |
1403 | ||
1404 | return rc; | |
1405 | } | |
1406 | ||
1407 | ||
1408 | /* | |
1409 | * cpqhp_return_board_resources | |
1410 | * | |
1411 | * this routine returns all resources allocated to a board to | |
1412 | * the available pool. | |
1413 | * | |
1414 | * returns 0 if success | |
1415 | */ | |
1416 | int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) | |
1417 | { | |
1418 | int rc = 0; | |
1419 | struct pci_resource *node; | |
1420 | struct pci_resource *t_node; | |
66bef8c0 | 1421 | dbg("%s\n", __func__); |
1da177e4 LT |
1422 | |
1423 | if (!func) | |
1424 | return 1; | |
1425 | ||
1426 | node = func->io_head; | |
1427 | func->io_head = NULL; | |
1428 | while (node) { | |
1429 | t_node = node->next; | |
1430 | return_resource(&(resources->io_head), node); | |
1431 | node = t_node; | |
1432 | } | |
1433 | ||
1434 | node = func->mem_head; | |
1435 | func->mem_head = NULL; | |
1436 | while (node) { | |
1437 | t_node = node->next; | |
1438 | return_resource(&(resources->mem_head), node); | |
1439 | node = t_node; | |
1440 | } | |
1441 | ||
1442 | node = func->p_mem_head; | |
1443 | func->p_mem_head = NULL; | |
1444 | while (node) { | |
1445 | t_node = node->next; | |
1446 | return_resource(&(resources->p_mem_head), node); | |
1447 | node = t_node; | |
1448 | } | |
1449 | ||
1450 | node = func->bus_head; | |
1451 | func->bus_head = NULL; | |
1452 | while (node) { | |
1453 | t_node = node->next; | |
1454 | return_resource(&(resources->bus_head), node); | |
1455 | node = t_node; | |
1456 | } | |
1457 | ||
1458 | rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); | |
1459 | rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); | |
1460 | rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); | |
1461 | rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); | |
1462 | ||
1463 | return rc; | |
1464 | } | |
1465 | ||
1466 | ||
1467 | /* | |
1468 | * cpqhp_destroy_resource_list | |
1469 | * | |
1470 | * Puts node back in the resource list pointed to by head | |
1471 | */ | |
1472 | void cpqhp_destroy_resource_list (struct resource_lists * resources) | |
1473 | { | |
1474 | struct pci_resource *res, *tres; | |
1475 | ||
1476 | res = resources->io_head; | |
1477 | resources->io_head = NULL; | |
1478 | ||
1479 | while (res) { | |
1480 | tres = res; | |
1481 | res = res->next; | |
1482 | kfree(tres); | |
1483 | } | |
1484 | ||
1485 | res = resources->mem_head; | |
1486 | resources->mem_head = NULL; | |
1487 | ||
1488 | while (res) { | |
1489 | tres = res; | |
1490 | res = res->next; | |
1491 | kfree(tres); | |
1492 | } | |
1493 | ||
1494 | res = resources->p_mem_head; | |
1495 | resources->p_mem_head = NULL; | |
1496 | ||
1497 | while (res) { | |
1498 | tres = res; | |
1499 | res = res->next; | |
1500 | kfree(tres); | |
1501 | } | |
1502 | ||
1503 | res = resources->bus_head; | |
1504 | resources->bus_head = NULL; | |
1505 | ||
1506 | while (res) { | |
1507 | tres = res; | |
1508 | res = res->next; | |
1509 | kfree(tres); | |
1510 | } | |
1511 | } | |
1512 | ||
1513 | ||
1514 | /* | |
1515 | * cpqhp_destroy_board_resources | |
1516 | * | |
1517 | * Puts node back in the resource list pointed to by head | |
1518 | */ | |
1519 | void cpqhp_destroy_board_resources (struct pci_func * func) | |
1520 | { | |
1521 | struct pci_resource *res, *tres; | |
1522 | ||
1523 | res = func->io_head; | |
1524 | func->io_head = NULL; | |
1525 | ||
1526 | while (res) { | |
1527 | tres = res; | |
1528 | res = res->next; | |
1529 | kfree(tres); | |
1530 | } | |
1531 | ||
1532 | res = func->mem_head; | |
1533 | func->mem_head = NULL; | |
1534 | ||
1535 | while (res) { | |
1536 | tres = res; | |
1537 | res = res->next; | |
1538 | kfree(tres); | |
1539 | } | |
1540 | ||
1541 | res = func->p_mem_head; | |
1542 | func->p_mem_head = NULL; | |
1543 | ||
1544 | while (res) { | |
1545 | tres = res; | |
1546 | res = res->next; | |
1547 | kfree(tres); | |
1548 | } | |
1549 | ||
1550 | res = func->bus_head; | |
1551 | func->bus_head = NULL; | |
1552 | ||
1553 | while (res) { | |
1554 | tres = res; | |
1555 | res = res->next; | |
1556 | kfree(tres); | |
1557 | } | |
1558 | } | |
1559 |