[PATCH] shpchp: use the PCI core for hotplug resource management
[linux-2.6-block.git] / drivers / pci / hotplug / shpchp_pci.c
1 /*
2  * Standard 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  * Copyright (C) 2003-2004 Intel Corporation
8  *
9  * All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or (at
14  * your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19  * NON INFRINGEMENT.  See the GNU General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
27  *
28  */
29
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/kernel.h>
33 #include <linux/types.h>
34 #include <linux/slab.h>
35 #include <linux/workqueue.h>
36 #include <linux/proc_fs.h>
37 #include <linux/pci.h>
38 #include "../pci.h"
39 #include "shpchp.h"
40
41 int shpchp_configure_device(struct slot *p_slot)
42 {
43         struct pci_dev *dev;
44         struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
45         int num, fn;
46
47         dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0));
48         if (dev) {
49                 err("Device %s already exists at %x:%x, cannot hot-add\n",
50                                 pci_name(dev), p_slot->bus, p_slot->device);
51                 return -EINVAL;
52         }
53
54         num = pci_scan_slot(parent, PCI_DEVFN(p_slot->device, 0));
55         if (num == 0) {
56                 err("No new device found\n");
57                 return -ENODEV;
58         }
59
60         for (fn = 0; fn < 8; fn++) {
61                 if (!(dev = pci_find_slot(p_slot->bus,
62                                         PCI_DEVFN(p_slot->device, fn))))
63                         continue;
64                 if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
65                         err("Cannot hot-add display device %s\n",
66                                         pci_name(dev));
67                         continue;
68                 }
69                 if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
70                                 (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
71                         /* Find an unused bus number for the new bridge */
72                         struct pci_bus *child;
73                         unsigned char busnr, start = parent->secondary;
74                         unsigned char end = parent->subordinate;
75                         for (busnr = start; busnr <= end; busnr++) {
76                                 if (!pci_find_bus(pci_domain_nr(parent),
77                                                         busnr))
78                                         break;
79                         }
80                         if (busnr >= end) {
81                                 err("No free bus for hot-added bridge\n");
82                                 continue;
83                         }
84                         child = pci_add_new_bus(parent, dev, busnr);
85                         if (!child) {
86                                 err("Cannot add new bus for %s\n",
87                                                 pci_name(dev));
88                                 continue;
89                         }
90                         child->subordinate = pci_do_scan_bus(child);
91                         pci_bus_size_bridges(child);
92                 }
93                 /* TBD: program firmware provided _HPP values */
94                 /* program_fw_provided_values(dev); */
95         }
96
97         pci_bus_assign_resources(parent);
98         pci_bus_add_devices(parent);
99         pci_enable_bridges(parent);
100         return 0;
101 }
102
103 int shpchp_unconfigure_device(struct pci_func* func) 
104 {
105         int rc = 0;
106         int j;
107         
108         dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus,
109                                 func->device, func->function);
110
111         for (j=0; j<8 ; j++) {
112                 struct pci_dev* temp = pci_find_slot(func->bus,
113                                 (func->device << 3) | j);
114                 if (temp) {
115                         pci_remove_bus_device(temp);
116                 }
117         }
118         return rc;
119 }
120
121 /* More PCI configuration routines; this time centered around hotplug controller */
122
123
124 /*
125  * shpchp_save_config
126  *
127  * Reads configuration for all slots in a PCI bus and saves info.
128  *
129  * Note:  For non-hot plug busses, the slot # saved is the device #
130  *
131  * returns 0 if success
132  */
133 int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num)
134 {
135         int rc;
136         u8 class_code;
137         u8 header_type;
138         u32 ID;
139         u8 secondary_bus;
140         struct pci_func *new_slot;
141         int sub_bus;
142         int FirstSupported;
143         int LastSupported;
144         int max_functions;
145         int function;
146         u8 DevError;
147         int device = 0;
148         int cloop = 0;
149         int stop_it;
150         int index;
151         int is_hot_plug = num_ctlr_slots || first_device_num;
152         struct pci_bus lpci_bus, *pci_bus;
153
154         dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__,
155                                 num_ctlr_slots, first_device_num);
156
157         memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
158         pci_bus = &lpci_bus;
159
160         dbg("%s: num_ctlr_slots = %d, first_device_num = %d\n", __FUNCTION__,
161                                 num_ctlr_slots, first_device_num);
162
163         /*   Decide which slots are supported */
164         if (is_hot_plug) {
165                 /*********************************
166                  *  is_hot_plug is the slot mask
167                  *********************************/
168                 FirstSupported = first_device_num;
169                 LastSupported = FirstSupported + num_ctlr_slots - 1;
170         } else {
171                 FirstSupported = 0;
172                 LastSupported = 0x1F;
173         }
174
175         dbg("FirstSupported = %d, LastSupported = %d\n", FirstSupported,
176                                         LastSupported);
177
178         /*   Save PCI configuration space for all devices in supported slots */
179         pci_bus->number = busnumber;
180         for (device = FirstSupported; device <= LastSupported; device++) {
181                 ID = 0xFFFFFFFF;
182                 rc = pci_bus_read_config_dword(pci_bus, PCI_DEVFN(device, 0),
183                                         PCI_VENDOR_ID, &ID);
184
185                 if (ID != 0xFFFFFFFF) {   /*  device in slot */
186                         rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
187                                         0x0B, &class_code);
188                         if (rc)
189                                 return rc;
190
191                         rc = pci_bus_read_config_byte(pci_bus, PCI_DEVFN(device, 0),
192                                         PCI_HEADER_TYPE, &header_type);
193                         if (rc)
194                                 return rc;
195
196                         dbg("class_code = %x, header_type = %x\n", class_code, header_type);
197
198                         /* If multi-function device, set max_functions to 8 */
199                         if (header_type & 0x80)
200                                 max_functions = 8;
201                         else
202                                 max_functions = 1;
203
204                         function = 0;
205
206                         do {
207                                 DevError = 0;
208
209                                 if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {   /* P-P Bridge */
210                                         /* Recurse the subordinate bus
211                                          * get the subordinate bus number
212                                          */
213                                         rc = pci_bus_read_config_byte(pci_bus,
214                                                 PCI_DEVFN(device, function), 
215                                                 PCI_SECONDARY_BUS, &secondary_bus);
216                                         if (rc) {
217                                                 return rc;
218                                         } else {
219                                                 sub_bus = (int) secondary_bus;
220
221                                                 /* Save secondary bus cfg spc with this recursive call. */
222                                                 rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
223                                                 if (rc)
224                                                         return rc;
225                                         }
226                                 }
227
228                                 index = 0;
229                                 new_slot = shpchp_slot_find(busnumber, device, index++);
230
231                                 dbg("new_slot = %p\n", new_slot);
232
233                                 while (new_slot && (new_slot->function != (u8) function)) {
234                                         new_slot = shpchp_slot_find(busnumber, device, index++);
235                                         dbg("new_slot = %p\n", new_slot);
236                                 }
237                                 if (!new_slot) {
238                                         /* Setup slot structure. */
239                                         new_slot = shpchp_slot_create(busnumber);
240                                         dbg("new_slot = %p\n", new_slot);
241
242                                         if (new_slot == NULL)
243                                                 return(1);
244                                 }
245
246                                 new_slot->bus = (u8) busnumber;
247                                 new_slot->device = (u8) device;
248                                 new_slot->function = (u8) function;
249                                 new_slot->is_a_board = 1;
250                                 new_slot->switch_save = 0x10;
251                                 new_slot->pwr_save = 1;
252                                 /* In case of unsupported board */
253                                 new_slot->status = DevError;
254                                 new_slot->pci_dev = pci_find_slot(new_slot->bus,
255                                         (new_slot->device << 3) | new_slot->function);
256                                 dbg("new_slot->pci_dev = %p\n", new_slot->pci_dev);
257
258                                 for (cloop = 0; cloop < 0x20; cloop++) {
259                                         rc = pci_bus_read_config_dword(pci_bus,
260                                                 PCI_DEVFN(device, function), 
261                                                 cloop << 2,
262                                                 (u32 *) &(new_slot->config_space [cloop]));
263                                         /* dbg("new_slot->config_space[%x] = %x\n",
264                                                 cloop, new_slot->config_space[cloop]); */
265                                         if (rc)
266                                                 return rc;
267                                 }
268
269                                 function++;
270
271                                 stop_it = 0;
272
273                                 /*  this loop skips to the next present function
274                                  *  reading in Class Code and Header type.
275                                  */
276
277                                 while ((function < max_functions)&&(!stop_it)) {
278                                         rc = pci_bus_read_config_dword(pci_bus,
279                                                 PCI_DEVFN(device, function),
280                                                 PCI_VENDOR_ID, &ID);
281
282                                         if (ID == 0xFFFFFFFF) {  /* nothing there. */
283                                                 function++;
284                                                 dbg("Nothing there\n");
285                                         } else {  /* Something there */
286                                                 rc = pci_bus_read_config_byte(pci_bus,
287                                                         PCI_DEVFN(device, function), 
288                                                         0x0B, &class_code);
289                                                 if (rc)
290                                                         return rc;
291
292                                                 rc = pci_bus_read_config_byte(pci_bus,
293                                                         PCI_DEVFN(device, function), 
294                                                         PCI_HEADER_TYPE, &header_type);
295                                                 if (rc)
296                                                         return rc;
297
298                                                 dbg("class_code = %x, header_type = %x\n",
299                                                         class_code, header_type);
300                                                 stop_it++;
301                                         }
302                                 }
303
304                         } while (function < max_functions);
305                         /* End of IF (device in slot?) */
306                 } else if (is_hot_plug) {
307                         /* Setup slot structure with entry for empty slot */
308                         new_slot = shpchp_slot_create(busnumber);
309
310                         if (new_slot == NULL) {
311                                 return(1);
312                         }
313                         dbg("new_slot = %p\n", new_slot);
314
315                         new_slot->bus = (u8) busnumber;
316                         new_slot->device = (u8) device;
317                         new_slot->function = 0;
318                         new_slot->is_a_board = 0;
319                         new_slot->presence_save = 0;
320                         new_slot->switch_save = 0;
321                 }
322         }                       /* End of FOR loop */
323
324         return(0);
325 }
326
327
328 /*
329  * shpchp_save_slot_config
330  *
331  * Saves configuration info for all PCI devices in a given slot
332  * including subordinate busses.
333  *
334  * returns 0 if success
335  */
336 int shpchp_save_slot_config(struct controller *ctrl, struct pci_func * new_slot)
337 {
338         int rc;
339         u8 class_code;
340         u8 header_type;
341         u32 ID;
342         u8 secondary_bus;
343         int sub_bus;
344         int max_functions;
345         int function;
346         int cloop = 0;
347         int stop_it;
348         struct pci_bus lpci_bus, *pci_bus;
349         memcpy(&lpci_bus, ctrl->pci_dev->subordinate, sizeof(lpci_bus));
350         pci_bus = &lpci_bus;
351         pci_bus->number = new_slot->bus;
352
353         ID = 0xFFFFFFFF;
354
355         pci_bus_read_config_dword(pci_bus, PCI_DEVFN(new_slot->device, 0),
356                                         PCI_VENDOR_ID, &ID);
357
358         if (ID != 0xFFFFFFFF) {   /*  device in slot */
359                 pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
360                                         0x0B, &class_code);
361
362                 pci_bus_read_config_byte(pci_bus, PCI_DEVFN(new_slot->device, 0),
363                                         PCI_HEADER_TYPE, &header_type);
364
365                 if (header_type & 0x80) /* Multi-function device */
366                         max_functions = 8;
367                 else
368                         max_functions = 1;
369
370                 function = 0;
371
372                 do {
373                         if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {     /* PCI-PCI Bridge */
374                                 /*  Recurse the subordinate bus */
375                                 pci_bus_read_config_byte(pci_bus,
376                                         PCI_DEVFN(new_slot->device, function), 
377                                         PCI_SECONDARY_BUS, &secondary_bus);
378
379                                 sub_bus = (int) secondary_bus;
380
381                                 /* Save the config headers for the secondary bus. */
382                                 rc = shpchp_save_config(ctrl, sub_bus, 0, 0);
383
384                                 if (rc)
385                                         return rc;
386
387                         }       /* End of IF */
388
389                         new_slot->status = 0;
390
391                         for (cloop = 0; cloop < 0x20; cloop++) {
392                                 pci_bus_read_config_dword(pci_bus,
393                                         PCI_DEVFN(new_slot->device, function), 
394                                         cloop << 2,
395                                         (u32 *) &(new_slot->config_space [cloop]));
396                         }
397
398                         function++;
399
400                         stop_it = 0;
401
402                         /*  this loop skips to the next present function
403                          *  reading in the Class Code and the Header type.
404                          */
405
406                         while ((function < max_functions) && (!stop_it)) {
407                                 pci_bus_read_config_dword(pci_bus,
408                                         PCI_DEVFN(new_slot->device, function),
409                                         PCI_VENDOR_ID, &ID);
410
411                                 if (ID == 0xFFFFFFFF) {  /* nothing there. */
412                                         function++;
413                                 } else {  /* Something there */
414                                         pci_bus_read_config_byte(pci_bus,
415                                                 PCI_DEVFN(new_slot->device, function),
416                                                 0x0B, &class_code);
417
418                                         pci_bus_read_config_byte(pci_bus,
419                                                 PCI_DEVFN(new_slot->device, function),
420                                                 PCI_HEADER_TYPE, &header_type);
421
422                                         stop_it++;
423                                 }
424                         }
425
426                 } while (function < max_functions);
427         }                       /* End of IF (device in slot?) */
428         else {
429                 return 2;
430         }
431
432         return 0;
433 }
434