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