ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / pci / hotplug / ibmphp_res.c
1 /*
2  * IBM Hot Plug Controller Driver
3  *
4  * Written By: Irene Zubarev, IBM Corporation
5  *
6  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
7  * Copyright (C) 2001,2002 IBM Corp.
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 <gregkh@us.ibm.com>
27  *
28  */
29
30 #include <linux/module.h>
31 #include <linux/slab.h>
32 #include <linux/pci.h>
33 #include <linux/list.h>
34 #include <linux/init.h>
35 #include "ibmphp.h"
36
37 static int flags = 0;           /* for testing */
38
39 static void update_resources (struct bus_node *bus_cur, int type, int rangeno);
40 static int once_over (void);
41 static int remove_ranges (struct bus_node *, struct bus_node *);
42 static int update_bridge_ranges (struct bus_node **);
43 static int add_range (int type, struct range_node *, struct bus_node *);
44 static void fix_resources (struct bus_node *);
45 static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
46
47 static LIST_HEAD(gbuses);
48 LIST_HEAD(ibmphp_res_head);
49
50 static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag)
51 {
52         struct bus_node * newbus;
53
54         if (!(curr) && !(flag)) {
55                 err ("NULL pointer passed\n");
56                 return NULL;
57         }
58
59         newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
60         if (!newbus) {
61                 err ("out of system memory\n");
62                 return NULL;
63         }
64
65         memset (newbus, 0, sizeof (struct bus_node));
66         if (flag)
67                 newbus->busno = busno;
68         else
69                 newbus->busno = curr->bus_num;
70         list_add_tail (&newbus->bus_list, &gbuses);
71         return newbus;
72 }
73
74 static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
75 {
76         struct resource_node *rs;
77         
78         if (!curr) {
79                 err ("NULL passed to allocate\n");
80                 return NULL;
81         }
82
83         rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
84         if (!rs) {
85                 err ("out of system memory\n");
86                 return NULL;
87         }
88         memset (rs, 0, sizeof (struct resource_node));
89         rs->busno = curr->bus_num;
90         rs->devfunc = curr->dev_fun;
91         rs->start = curr->start_addr;
92         rs->end = curr->end_addr;
93         rs->len = curr->end_addr - curr->start_addr + 1;
94         return rs;
95 }
96
97 static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
98 {
99         struct bus_node * newbus;
100         struct range_node *newrange;
101         u8 num_ranges = 0;
102
103         if (first_bus) {
104                 newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL);
105                 if (!newbus) {
106                         err ("out of system memory.\n");
107                         return -ENOMEM;
108                 }
109                 memset (newbus, 0, sizeof (struct bus_node));
110                 newbus->busno = curr->bus_num;
111         } else {
112                 newbus = *new_bus;
113                 switch (flag) {
114                         case MEM:
115                                 num_ranges = newbus->noMemRanges;
116                                 break;
117                         case PFMEM:
118                                 num_ranges = newbus->noPFMemRanges;
119                                 break;
120                         case IO:
121                                 num_ranges = newbus->noIORanges;
122                                 break;
123                 }
124         }
125
126         newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL);
127         if (!newrange) {
128                 if (first_bus)
129                         kfree (newbus);
130                 err ("out of system memory\n");
131                 return -ENOMEM;
132         }
133         memset (newrange, 0, sizeof (struct range_node));
134         newrange->start = curr->start_addr;
135         newrange->end = curr->end_addr;
136                 
137         if (first_bus || (!num_ranges))
138                 newrange->rangeno = 1;
139         else {
140                 /* need to insert our range */
141                 add_range (flag, newrange, newbus);
142                 debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end);
143         }
144
145         switch (flag) {
146                 case MEM:
147                         newbus->rangeMem = newrange;
148                         if (first_bus)
149                                 newbus->noMemRanges = 1;
150                         else {
151                                 debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
152                                 ++newbus->noMemRanges;
153                                 fix_resources (newbus);
154                         }
155                         break;
156                 case IO:
157                         newbus->rangeIO = newrange;
158                         if (first_bus)
159                                 newbus->noIORanges = 1;
160                         else {
161                                 debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
162                                 ++newbus->noIORanges;
163                                 fix_resources (newbus);
164                         }
165                         break;
166                 case PFMEM:
167                         newbus->rangePFMem = newrange;
168                         if (first_bus)
169                                 newbus->noPFMemRanges = 1;
170                         else {  
171                                 debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
172                                 ++newbus->noPFMemRanges;
173                                 fix_resources (newbus);
174                         }
175
176                         break;
177         }
178
179         *new_bus = newbus;
180         *new_range = newrange;
181         return 0;
182 }
183
184
185 /* Notes:
186  * 1. The ranges are ordered.  The buses are not ordered.  (First come)
187  *
188  * 2. If cannot allocate out of PFMem range, allocate from Mem ranges.  PFmemFromMem
189  * are not sorted. (no need since use mem node). To not change the entire code, we
190  * also add mem node whenever this case happens so as not to change
191  * ibmphp_check_mem_resource etc (and since it really is taking Mem resource)
192  */
193
194 /*****************************************************************************
195  * This is the Resource Management initialization function.  It will go through
196  * the Resource list taken from EBDA and fill in this module's data structures
197  *
198  * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, 
199  * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW
200  *
201  * Input: ptr to the head of the resource list from EBDA
202  * Output: 0, -1 or error codes
203  ***************************************************************************/
204 int __init ibmphp_rsrc_init (void)
205 {
206         struct ebda_pci_rsrc *curr;
207         struct range_node *newrange = NULL;
208         struct bus_node *newbus = NULL;
209         struct bus_node *bus_cur;
210         struct bus_node *bus_prev;
211         struct list_head *tmp;
212         struct resource_node *new_io = NULL;
213         struct resource_node *new_mem = NULL;
214         struct resource_node *new_pfmem = NULL;
215         int rc;
216         struct list_head *tmp_ebda;
217
218         list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) {
219                 curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list);
220                 if (!(curr->rsrc_type & PCIDEVMASK)) {
221                         /* EBDA still lists non PCI devices, so ignore... */
222                         debug ("this is not a PCI DEVICE in rsrc_init, please take care\n");
223                         // continue;
224                 }
225
226                 /* this is a primary bus resource */
227                 if (curr->rsrc_type & PRIMARYBUSMASK) {
228                         /* memory */
229                         if ((curr->rsrc_type & RESTYPE) == MMASK) {
230                                 /* no bus structure exists in place yet */
231                                 if (list_empty (&gbuses)) {
232                                         if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))
233                                                 return rc;
234                                         list_add_tail (&newbus->bus_list, &gbuses);
235                                         debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
236                                 } else {
237                                         bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
238                                         /* found our bus */
239                                         if (bus_cur) {
240                                                 rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0);
241                                                 if (rc)
242                                                         return rc;
243                                         } else {
244                                                 /* went through all the buses and didn't find ours, need to create a new bus node */
245                                                 if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1)))
246                                                         return rc;
247
248                                                 list_add_tail (&newbus->bus_list, &gbuses);
249                                                 debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
250                                         }
251                                 }
252                         } else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
253                                 /* prefetchable memory */
254                                 if (list_empty (&gbuses)) {
255                                         /* no bus structure exists in place yet */
256                                         if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))
257                                                 return rc;
258                                         list_add_tail (&newbus->bus_list, &gbuses);
259                                         debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
260                                 } else {
261                                         bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
262                                         if (bus_cur) {
263                                                 /* found our bus */
264                                                 rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0);
265                                                 if (rc)
266                                                         return rc;
267                                         } else {
268                                                 /* went through all the buses and didn't find ours, need to create a new bus node */
269                                                 if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1)))
270                                                         return rc;
271                                                 list_add_tail (&newbus->bus_list, &gbuses);
272                                                 debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
273                                         }
274                                 }
275                         } else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
276                                 /* IO */
277                                 if (list_empty (&gbuses)) {
278                                         /* no bus structure exists in place yet */
279                                         if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))
280                                                 return rc;
281                                         list_add_tail (&newbus->bus_list, &gbuses);
282                                         debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
283                                 } else {
284                                         bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1);
285                                         if (bus_cur) {
286                                                 rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0);
287                                                 if (rc)
288                                                         return rc;
289                                         } else {
290                                                 /* went through all the buses and didn't find ours, need to create a new bus node */
291                                                 if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1)))
292                                                         return rc;
293                                                 list_add_tail (&newbus->bus_list, &gbuses);
294                                                 debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end);
295                                         }
296                                 }
297
298                         } else {
299                                 ;       /* type is reserved  WHAT TO DO IN THIS CASE???
300                                            NOTHING TO DO??? */
301                         }
302                 } else {
303                         /* regular pci device resource */
304                         if ((curr->rsrc_type & RESTYPE) == MMASK) {
305                                 /* Memory resource */
306                                 new_mem = alloc_resources (curr);
307                                 if (!new_mem)
308                                         return -ENOMEM;
309                                 new_mem->type = MEM;
310                                 /*
311                                  * if it didn't find the bus, means PCI dev
312                                  * came b4 the Primary Bus info, so need to
313                                  * create a bus rangeno becomes a problem...
314                                  * assign a -1 and then update once the range
315                                  * actually appears...
316                                  */
317                                 if (ibmphp_add_resource (new_mem) < 0) {
318                                         newbus = alloc_error_bus (curr, 0, 0);
319                                         if (!newbus)
320                                                 return -ENOMEM;
321                                         newbus->firstMem = new_mem;
322                                         ++newbus->needMemUpdate;
323                                         new_mem->rangeno = -1;
324                                 }
325                                 debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end);
326
327                         } else if ((curr->rsrc_type & RESTYPE) == PFMASK) {
328                                 /* PFMemory resource */
329                                 new_pfmem = alloc_resources (curr);
330                                 if (!new_pfmem)
331                                         return -ENOMEM;
332                                 new_pfmem->type = PFMEM;
333                                 new_pfmem->fromMem = FALSE;
334                                 if (ibmphp_add_resource (new_pfmem) < 0) {
335                                         newbus = alloc_error_bus (curr, 0, 0);
336                                         if (!newbus)
337                                                 return -ENOMEM;
338                                         newbus->firstPFMem = new_pfmem;
339                                         ++newbus->needPFMemUpdate;
340                                         new_pfmem->rangeno = -1;
341                                 }
342
343                                 debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end);
344                         } else if ((curr->rsrc_type & RESTYPE) == IOMASK) {
345                                 /* IO resource */
346                                 new_io = alloc_resources (curr);
347                                 if (!new_io)
348                                         return -ENOMEM;
349                                 new_io->type = IO;
350
351                                 /*
352                                  * if it didn't find the bus, means PCI dev
353                                  * came b4 the Primary Bus info, so need to
354                                  * create a bus rangeno becomes a problem...
355                                  * Can assign a -1 and then update once the
356                                  * range actually appears...
357                                  */
358                                 if (ibmphp_add_resource (new_io) < 0) {
359                                         newbus = alloc_error_bus (curr, 0, 0);
360                                         if (!newbus)
361                                                 return -ENOMEM;
362                                         newbus->firstIO = new_io;
363                                         ++newbus->needIOUpdate;
364                                         new_io->rangeno = -1;
365                                 }
366                                 debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end);
367                         }
368                 }
369         }
370
371         list_for_each (tmp, &gbuses) {
372                 bus_cur = list_entry (tmp, struct bus_node, bus_list);
373                 /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */
374                 rc = update_bridge_ranges (&bus_cur);
375                 if (rc)
376                         return rc;
377         }
378         rc = once_over ();  /* This is to align ranges (so no -1) */
379         if (rc)
380                 return rc;
381         return 0;
382 }
383
384 /********************************************************************************
385  * This function adds a range into a sorted list of ranges per bus for a particular
386  * range type, it then calls another routine to update the range numbers on the
387  * pci devices' resources for the appropriate resource
388  *
389  * Input: type of the resource, range to add, current bus
390  * Output: 0 or -1, bus and range ptrs 
391  ********************************************************************************/
392 static int add_range (int type, struct range_node *range, struct bus_node *bus_cur)
393 {
394         struct range_node *range_cur = NULL;
395         struct range_node *range_prev;
396         int count = 0, i_init;
397         int noRanges = 0;
398
399         switch (type) {
400                 case MEM:
401                         range_cur = bus_cur->rangeMem;
402                         noRanges = bus_cur->noMemRanges;
403                         break;
404                 case PFMEM:
405                         range_cur = bus_cur->rangePFMem;
406                         noRanges = bus_cur->noPFMemRanges;
407                         break;
408                 case IO:
409                         range_cur = bus_cur->rangeIO;
410                         noRanges = bus_cur->noIORanges;
411                         break;
412         }
413
414         range_prev = NULL;
415         while (range_cur) {
416                 if (range->start < range_cur->start)
417                         break;
418                 range_prev = range_cur;
419                 range_cur = range_cur->next;
420                 count = count + 1;
421         }
422         if (!count) {
423                 /* our range will go at the beginning of the list */
424                 switch (type) {
425                         case MEM:
426                                 bus_cur->rangeMem = range;
427                                 break;
428                         case PFMEM:
429                                 bus_cur->rangePFMem = range;
430                                 break;
431                         case IO:
432                                 bus_cur->rangeIO = range;
433                                 break;
434                 }
435                 range->next = range_cur;
436                 range->rangeno = 1;
437                 i_init = 0;
438         } else if (!range_cur) {
439                 /* our range will go at the end of the list */
440                 range->next = NULL;
441                 range_prev->next = range;
442                 range->rangeno = range_prev->rangeno + 1;
443                 return 0;
444         } else {
445                 /* the range is in the middle */
446                 range_prev->next = range;
447                 range->next = range_cur;
448                 range->rangeno = range_cur->rangeno;
449                 i_init = range_prev->rangeno;
450         }
451
452         for (count = i_init; count < noRanges; ++count) {
453                 ++range_cur->rangeno;
454                 range_cur = range_cur->next;
455         }
456
457         update_resources (bus_cur, type, i_init + 1);
458         return 0;
459 }
460
461 /*******************************************************************************
462  * This routine goes through the list of resources of type 'type' and updates
463  * the range numbers that they correspond to.  It was called from add_range fnc
464  *
465  * Input: bus, type of the resource, the rangeno starting from which to update
466  ******************************************************************************/
467 static void update_resources (struct bus_node *bus_cur, int type, int rangeno)
468 {
469         struct resource_node *res = NULL;
470         u8 eol = FALSE; /* end of list indicator */
471
472         switch (type) {
473                 case MEM:
474                         if (bus_cur->firstMem) 
475                                 res = bus_cur->firstMem;
476                         break;
477                 case PFMEM:
478                         if (bus_cur->firstPFMem)
479                                 res = bus_cur->firstPFMem;
480                         break;
481                 case IO:
482                         if (bus_cur->firstIO)
483                                 res = bus_cur->firstIO;
484                         break;
485         }
486
487         if (res) {
488                 while (res) {
489                         if (res->rangeno == rangeno)
490                                 break;
491                         if (res->next)
492                                 res = res->next;
493                         else if (res->nextRange)
494                                 res = res->nextRange;
495                         else {
496                                 eol = TRUE;
497                                 break;
498                         }
499                 }
500
501                 if (!eol) {
502                         /* found the range */
503                         while (res) {
504                                 ++res->rangeno;
505                                 res = res->next;
506                         }
507                 }
508         }
509 }
510
511 static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range)
512 {
513         char * str = "";
514         switch (res->type) {
515                 case IO:
516                         str = "io";
517                         break;
518                 case MEM:
519                         str = "mem";
520                         break;
521                 case PFMEM:
522                         str = "pfmem";
523                         break;
524         }
525
526         while (res) {
527                 if (res->rangeno == -1) {
528                         while (range) {
529                                 if ((res->start >= range->start) && (res->end <= range->end)) {
530                                         res->rangeno = range->rangeno;
531                                         debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno);
532                                         switch (res->type) {
533                                                 case IO:
534                                                         --bus_cur->needIOUpdate;
535                                                         break;
536                                                 case MEM:
537                                                         --bus_cur->needMemUpdate;
538                                                         break;
539                                                 case PFMEM:
540                                                         --bus_cur->needPFMemUpdate;
541                                                         break;
542                                         }
543                                         break;
544                                 }
545                                 range = range->next;
546                         }
547                 }
548                 if (res->next)
549                         res = res->next;
550                 else
551                         res = res->nextRange;
552         }
553
554 }
555
556 /*****************************************************************************
557  * This routine reassigns the range numbers to the resources that had a -1
558  * This case can happen only if upon initialization, resources taken by pci dev
559  * appear in EBDA before the resources allocated for that bus, since we don't
560  * know the range, we assign -1, and this routine is called after a new range
561  * is assigned to see the resources with unknown range belong to the added range
562  *
563  * Input: current bus
564  * Output: none, list of resources for that bus are fixed if can be
565  *******************************************************************************/
566 static void fix_resources (struct bus_node *bus_cur)
567 {
568         struct range_node *range;
569         struct resource_node *res;
570
571         debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno);
572
573         if (bus_cur->needIOUpdate) {
574                 res = bus_cur->firstIO;
575                 range = bus_cur->rangeIO;
576                 fix_me (res, bus_cur, range);
577         }
578         if (bus_cur->needMemUpdate) {
579                 res = bus_cur->firstMem;
580                 range = bus_cur->rangeMem;
581                 fix_me (res, bus_cur, range);
582         }
583         if (bus_cur->needPFMemUpdate) {
584                 res = bus_cur->firstPFMem;
585                 range = bus_cur->rangePFMem;
586                 fix_me (res, bus_cur, range);
587         }
588 }
589
590 /*******************************************************************************
591  * This routine adds a resource to the list of resources to the appropriate bus 
592  * based on their resource type and sorted by their starting addresses.  It assigns
593  * the ptrs to next and nextRange if needed.
594  *
595  * Input: resource ptr
596  * Output: ptrs assigned (to the node)
597  * 0 or -1
598  *******************************************************************************/
599 int ibmphp_add_resource (struct resource_node *res)
600 {
601         struct resource_node *res_cur;
602         struct resource_node *res_prev;
603         struct bus_node *bus_cur;
604         struct range_node *range_cur = NULL;
605         struct resource_node *res_start = NULL;
606
607         debug ("%s - enter\n", __FUNCTION__);
608
609         if (!res) {
610                 err ("NULL passed to add\n");
611                 return -ENODEV;
612         }
613         
614         bus_cur = find_bus_wprev (res->busno, NULL, 0);
615         
616         if (!bus_cur) {
617                 /* didn't find a bus, smth's wrong!!! */
618                 debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");
619                 return -ENODEV;
620         }
621
622         /* Normal case */
623         switch (res->type) {
624                 case IO:
625                         range_cur = bus_cur->rangeIO;
626                         res_start = bus_cur->firstIO;
627                         break;
628                 case MEM:
629                         range_cur = bus_cur->rangeMem;
630                         res_start = bus_cur->firstMem;
631                         break;
632                 case PFMEM:
633                         range_cur = bus_cur->rangePFMem;
634                         res_start = bus_cur->firstPFMem;
635                         break;
636                 default:
637                         err ("cannot read the type of the resource to add... problem\n");
638                         return -EINVAL;
639         }
640         while (range_cur) {
641                 if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) {
642                         res->rangeno = range_cur->rangeno;
643                         break;
644                 }
645                 range_cur = range_cur->next;
646         }
647
648         /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
649          * this is again the case of rangeno = -1
650          * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
651          */
652
653         if (!range_cur) {
654                 switch (res->type) {
655                         case IO:
656                                 ++bus_cur->needIOUpdate;                                        
657                                 break;
658                         case MEM:
659                                 ++bus_cur->needMemUpdate;
660                                 break;
661                         case PFMEM:
662                                 ++bus_cur->needPFMemUpdate;
663                                 break;
664                 }
665                 res->rangeno = -1;
666         }
667         
668         debug ("The range is %d\n", res->rangeno);
669         if (!res_start) {
670                 /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */
671                 switch (res->type) {
672                         case IO:
673                                 bus_cur->firstIO = res;                                 
674                                 break;
675                         case MEM:
676                                 bus_cur->firstMem = res;
677                                 break;
678                         case PFMEM:
679                                 bus_cur->firstPFMem = res;
680                                 break;
681                 }       
682                 res->next = NULL;
683                 res->nextRange = NULL;
684         } else {
685                 res_cur = res_start;
686                 res_prev = NULL;
687
688                 debug ("res_cur->rangeno is %d\n", res_cur->rangeno);
689
690                 while (res_cur) {
691                         if (res_cur->rangeno >= res->rangeno)
692                                 break;
693                         res_prev = res_cur;
694                         if (res_cur->next)
695                                 res_cur = res_cur->next;
696                         else
697                                 res_cur = res_cur->nextRange;
698                 }
699
700                 if (!res_cur) {
701                         /* at the end of the resource list */
702                         debug ("i should be here, [%x - %x]\n", res->start, res->end);
703                         res_prev->nextRange = res;
704                         res->next = NULL;
705                         res->nextRange = NULL;
706                 } else if (res_cur->rangeno == res->rangeno) {
707                         /* in the same range */
708                         while (res_cur) {
709                                 if (res->start < res_cur->start)
710                                         break;
711                                 res_prev = res_cur;
712                                 res_cur = res_cur->next;
713                         }
714                         if (!res_cur) {
715                                 /* the last resource in this range */
716                                 res_prev->next = res;
717                                 res->next = NULL;
718                                 res->nextRange = res_prev->nextRange;
719                                 res_prev->nextRange = NULL;
720                         } else if (res->start < res_cur->start) {
721                                 /* at the beginning or middle of the range */
722                                 if (!res_prev)  {
723                                         switch (res->type) {
724                                                 case IO:
725                                                         bus_cur->firstIO = res;
726                                                         break;
727                                                 case MEM:
728                                                         bus_cur->firstMem = res;
729                                                         break;
730                                                 case PFMEM:
731                                                         bus_cur->firstPFMem = res;
732                                                         break;
733                                         }
734                                 } else if (res_prev->rangeno == res_cur->rangeno)
735                                         res_prev->next = res;
736                                 else
737                                         res_prev->nextRange = res;
738
739                                 res->next = res_cur;
740                                 res->nextRange = NULL;
741                         }
742                 } else {
743                         /* this is the case where it is 1st occurrence of the range */
744                         if (!res_prev) {
745                                 /* at the beginning of the resource list */
746                                 res->next = NULL;
747                                 switch (res->type) {
748                                         case IO:
749                                                 res->nextRange = bus_cur->firstIO;
750                                                 bus_cur->firstIO = res;
751                                                 break;
752                                         case MEM:
753                                                 res->nextRange = bus_cur->firstMem;
754                                                 bus_cur->firstMem = res;
755                                                 break;
756                                         case PFMEM:
757                                                 res->nextRange = bus_cur->firstPFMem;
758                                                 bus_cur->firstPFMem = res;
759                                                 break;
760                                 }
761                         } else if (res_cur->rangeno > res->rangeno) {
762                                 /* in the middle of the resource list */
763                                 res_prev->nextRange = res;
764                                 res->next = NULL;
765                                 res->nextRange = res_cur;
766                         }
767                 }
768         }
769
770         debug ("%s - exit\n", __FUNCTION__);
771         return 0;
772 }
773
774 /****************************************************************************
775  * This routine will remove the resource from the list of resources
776  *
777  * Input: io, mem, and/or pfmem resource to be deleted
778  * Ouput: modified resource list
779  *        0 or error code
780  ****************************************************************************/
781 int ibmphp_remove_resource (struct resource_node *res)
782 {
783         struct bus_node *bus_cur;
784         struct resource_node *res_cur = NULL;
785         struct resource_node *res_prev;
786         struct resource_node *mem_cur;
787         char * type = "";
788
789         if (!res)  {
790                 err ("resource to remove is NULL\n");
791                 return -ENODEV;
792         }
793
794         bus_cur = find_bus_wprev (res->busno, NULL, 0);
795
796         if (!bus_cur) {
797                 err ("cannot find corresponding bus of the io resource to remove  "
798                         "bailing out...\n");
799                 return -ENODEV;
800         }
801
802         switch (res->type) {
803                 case IO:
804                         res_cur = bus_cur->firstIO;
805                         type = "io";
806                         break;
807                 case MEM:
808                         res_cur = bus_cur->firstMem;
809                         type = "mem";
810                         break;
811                 case PFMEM:
812                         res_cur = bus_cur->firstPFMem;
813                         type = "pfmem";
814                         break;
815                 default:
816                         err ("unknown type for resource to remove\n");
817                         return -EINVAL;
818         }
819         res_prev = NULL;
820
821         while (res_cur) {
822                 if ((res_cur->start == res->start) && (res_cur->end == res->end))
823                         break;
824                 res_prev = res_cur;
825                 if (res_cur->next)
826                         res_cur = res_cur->next;
827                 else
828                         res_cur = res_cur->nextRange;
829         }
830
831         if (!res_cur) {
832                 if (res->type == PFMEM) {
833                         /* 
834                          * case where pfmem might be in the PFMemFromMem list
835                          * so will also need to remove the corresponding mem
836                          * entry
837                          */
838                         res_cur = bus_cur->firstPFMemFromMem;
839                         res_prev = NULL;
840
841                         while (res_cur) {
842                                 if ((res_cur->start == res->start) && (res_cur->end == res->end)) {
843                                         mem_cur = bus_cur->firstMem;
844                                         while (mem_cur) {
845                                                 if ((mem_cur->start == res_cur->start)
846                                                     && (mem_cur->end == res_cur->end))
847                                                         break;
848                                                 if (mem_cur->next)
849                                                         mem_cur = mem_cur->next;
850                                                 else
851                                                         mem_cur = mem_cur->nextRange;
852                                         }
853                                         if (!mem_cur) {
854                                                 err ("cannot find corresponding mem node for pfmem...\n");
855                                                 return -EINVAL;
856                                         }
857
858                                         ibmphp_remove_resource (mem_cur);
859                                         if (!res_prev)
860                                                 bus_cur->firstPFMemFromMem = res_cur->next;
861                                         else
862                                                 res_prev->next = res_cur->next;
863                                         kfree (res_cur);
864                                         return 0;
865                                 }
866                                 res_prev = res_cur;
867                                 if (res_cur->next)
868                                         res_cur = res_cur->next;
869                                 else
870                                         res_cur = res_cur->nextRange;
871                         }
872                         if (!res_cur) {
873                                 err ("cannot find pfmem to delete...\n");
874                                 return -EINVAL;
875                         }
876                 } else {
877                         err ("the %s resource is not in the list to be deleted...\n", type);
878                         return -EINVAL;
879                 }
880         }
881         if (!res_prev) {
882                 /* first device to be deleted */
883                 if (res_cur->next) {
884                         switch (res->type) {
885                                 case IO:
886                                         bus_cur->firstIO = res_cur->next;
887                                         break;
888                                 case MEM:
889                                         bus_cur->firstMem = res_cur->next;
890                                         break;
891                                 case PFMEM:
892                                         bus_cur->firstPFMem = res_cur->next;
893                                         break;
894                         }
895                 } else if (res_cur->nextRange) {
896                         switch (res->type) {
897                                 case IO:
898                                         bus_cur->firstIO = res_cur->nextRange;
899                                         break;
900                                 case MEM:
901                                         bus_cur->firstMem = res_cur->nextRange;
902                                         break;
903                                 case PFMEM:
904                                         bus_cur->firstPFMem = res_cur->nextRange;
905                                         break;
906                         }
907                 } else {
908                         switch (res->type) {
909                                 case IO:
910                                         bus_cur->firstIO = NULL;
911                                         break;
912                                 case MEM:
913                                         bus_cur->firstMem = NULL;
914                                         break;
915                                 case PFMEM:
916                                         bus_cur->firstPFMem = NULL;
917                                         break;
918                         }
919                 }
920                 kfree (res_cur);
921                 return 0;
922         } else {
923                 if (res_cur->next) {
924                         if (res_prev->rangeno == res_cur->rangeno)
925                                 res_prev->next = res_cur->next;
926                         else
927                                 res_prev->nextRange = res_cur->next;
928                 } else if (res_cur->nextRange) {
929                         res_prev->next = NULL;
930                         res_prev->nextRange = res_cur->nextRange;
931                 } else {
932                         res_prev->next = NULL;
933                         res_prev->nextRange = NULL;
934                 }
935                 kfree (res_cur);
936                 return 0;
937         }
938
939         return 0;
940 }
941
942 static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res)
943 {
944         struct range_node * range = NULL;
945
946         switch (res->type) {
947                 case IO:
948                         range = bus_cur->rangeIO;
949                         break;
950                 case MEM:
951                         range = bus_cur->rangeMem;
952                         break;
953                 case PFMEM:
954                         range = bus_cur->rangePFMem;
955                         break;
956                 default:
957                         err ("cannot read resource type in find_range\n");
958         }
959
960         while (range) {
961                 if (res->rangeno == range->rangeno)
962                         break;
963                 range = range->next;
964         }
965         return range;
966 }
967
968 /*****************************************************************************
969  * This routine will check to make sure the io/mem/pfmem->len that the device asked for 
970  * can fit w/i our list of available IO/MEM/PFMEM resources.  If cannot, returns -EINVAL,
971  * otherwise, returns 0
972  *
973  * Input: resource
974  * Ouput: the correct start and end address are inputted into the resource node,
975  *        0 or -EINVAL
976  *****************************************************************************/
977 int ibmphp_check_resource (struct resource_node *res, u8 bridge)
978 {
979         struct bus_node *bus_cur;
980         struct range_node *range = NULL;
981         struct resource_node *res_prev;
982         struct resource_node *res_cur = NULL;
983         u32 len_cur = 0, start_cur = 0, len_tmp = 0;
984         int noranges = 0;
985         u32 tmp_start;          /* this is to make sure start address is divisible by the length needed */
986         u32 tmp_divide;
987         u8 flag = FALSE;
988
989         if (!res)
990                 return -EINVAL;
991
992         if (bridge) {
993                 /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/
994                 if (res->type == IO)
995                         tmp_divide = IOBRIDGE;
996                 else
997                         tmp_divide = MEMBRIDGE;
998         } else
999                 tmp_divide = res->len;
1000
1001         bus_cur = find_bus_wprev (res->busno, NULL, 0);
1002
1003         if (!bus_cur) {
1004                 /* didn't find a bus, smth's wrong!!! */
1005                 debug ("no bus in the system, either pci_dev's wrong or allocation failed\n");
1006                 return -EINVAL;
1007         }
1008
1009         debug ("%s - enter\n", __FUNCTION__);
1010         debug ("bus_cur->busno is %d\n", bus_cur->busno);
1011
1012         /* This is a quick fix to not mess up with the code very much.  i.e.,
1013          * 2000-2fff, len = 1000, but when we compare, we need it to be fff */
1014         res->len -= 1;
1015
1016         switch (res->type) {
1017                 case IO:
1018                         res_cur = bus_cur->firstIO;
1019                         noranges = bus_cur->noIORanges;
1020                         break;
1021                 case MEM:
1022                         res_cur = bus_cur->firstMem;
1023                         noranges = bus_cur->noMemRanges;
1024                         break;
1025                 case PFMEM:
1026                         res_cur = bus_cur->firstPFMem;
1027                         noranges = bus_cur->noPFMemRanges;
1028                         break;
1029                 default:
1030                         err ("wrong type of resource to check\n");
1031                         return -EINVAL;
1032         }
1033         res_prev = NULL;
1034
1035         while (res_cur) {
1036                 range = find_range (bus_cur, res_cur);
1037                 debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno);
1038
1039                 if (!range) {
1040                         err ("no range for the device exists... bailing out...\n");
1041                         return -EINVAL;
1042                 }
1043
1044                 /* found our range */
1045                 if (!res_prev) {
1046                         /* first time in the loop */
1047                         if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {
1048                                 debug ("len_tmp = %x\n", len_tmp);
1049
1050                                 if ((len_tmp < len_cur) || (len_cur == 0)) {
1051
1052                                         if ((range->start % tmp_divide) == 0) {
1053                                                 /* just perfect, starting address is divisible by length */
1054                                                 flag = TRUE;
1055                                                 len_cur = len_tmp;
1056                                                 start_cur = range->start;
1057                                         } else {
1058                                                 /* Needs adjusting */
1059                                                 tmp_start = range->start;
1060                                                 flag = FALSE;
1061
1062                                                 while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
1063                                                         if ((tmp_start % tmp_divide) == 0) {
1064                                                                 flag = TRUE;
1065                                                                 len_cur = len_tmp;
1066                                                                 start_cur = tmp_start;
1067                                                                 break;
1068                                                         }
1069                                                         tmp_start += tmp_divide - tmp_start % tmp_divide;
1070                                                         if (tmp_start >= res_cur->start - 1)
1071                                                                 break;
1072                                                 }
1073                                         }
1074                         
1075                                         if (flag && len_cur == res->len) {
1076                                                 debug ("but we are not here, right?\n");
1077                                                 res->start = start_cur;
1078                                                 res->len += 1; /* To restore the balance */
1079                                                 res->end = res->start + res->len - 1;
1080                                                 return 0;
1081                                         }
1082                                 }
1083                         }
1084                 }
1085                 if (!res_cur->next) {
1086                         /* last device on the range */
1087                         if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) {
1088                                 debug ("len_tmp = %x\n", len_tmp);
1089                                 if ((len_tmp < len_cur) || (len_cur == 0)) {
1090
1091                                         if (((res_cur->end + 1) % tmp_divide) == 0) {
1092                                                 /* just perfect, starting address is divisible by length */
1093                                                 flag = TRUE;
1094                                                 len_cur = len_tmp;
1095                                                 start_cur = res_cur->end + 1;
1096                                         } else {
1097                                                 /* Needs adjusting */
1098                                                 tmp_start = res_cur->end + 1;
1099                                                 flag = FALSE;
1100
1101                                                 while ((len_tmp = range->end - tmp_start) >= res->len) {
1102                                                         if ((tmp_start % tmp_divide) == 0) {
1103                                                                 flag = TRUE;
1104                                                                 len_cur = len_tmp;
1105                                                                 start_cur = tmp_start;
1106                                                                 break;
1107                                                         }
1108                                                         tmp_start += tmp_divide - tmp_start % tmp_divide;
1109                                                         if (tmp_start >= range->end)
1110                                                                 break;
1111                                                 }
1112                                         }
1113                                         if (flag && len_cur == res->len) {
1114                                                 res->start = start_cur;
1115                                                 res->len += 1; /* To restore the balance */
1116                                                 res->end = res->start + res->len - 1;
1117                                                 return 0;
1118                                         }
1119                                 }
1120                         }
1121                 }
1122
1123                 if (res_prev) {
1124                         if (res_prev->rangeno != res_cur->rangeno) {
1125                                 /* 1st device on this range */
1126                                 if ((res_cur->start != range->start) && 
1127                                         ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) {
1128                                         if ((len_tmp < len_cur) || (len_cur == 0)) {
1129                                                 if ((range->start % tmp_divide) == 0) { 
1130                                                         /* just perfect, starting address is divisible by length */
1131                                                         flag = TRUE;
1132                                                         len_cur = len_tmp;
1133                                                         start_cur = range->start;
1134                                                 } else {
1135                                                         /* Needs adjusting */
1136                                                         tmp_start = range->start;
1137                                                         flag = FALSE;
1138
1139                                                         while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
1140                                                                 if ((tmp_start % tmp_divide) == 0) {
1141                                                                         flag = TRUE;
1142                                                                         len_cur = len_tmp;
1143                                                                         start_cur = tmp_start;
1144                                                                         break;
1145                                                                 }
1146                                                                 tmp_start += tmp_divide - tmp_start % tmp_divide;
1147                                                                 if (tmp_start >= res_cur->start - 1)
1148                                                                         break;
1149                                                         }
1150                                                 }
1151
1152                                                 if (flag && len_cur == res->len) {
1153                                                         res->start = start_cur;
1154                                                         res->len += 1; /* To restore the balance */
1155                                                         res->end = res->start + res->len - 1;
1156                                                         return 0;
1157                                                 }
1158                                         }
1159                                 }
1160                         } else {
1161                                 /* in the same range */
1162                                 if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) {
1163                                         if ((len_tmp < len_cur) || (len_cur == 0)) {
1164                                                 if (((res_prev->end + 1) % tmp_divide) == 0) {
1165                                                         /* just perfect, starting address's divisible by length */
1166                                                         flag = TRUE;
1167                                                         len_cur = len_tmp;
1168                                                         start_cur = res_prev->end + 1;
1169                                                 } else {
1170                                                         /* Needs adjusting */
1171                                                         tmp_start = res_prev->end + 1;
1172                                                         flag = FALSE;
1173
1174                                                         while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) {
1175                                                                 if ((tmp_start % tmp_divide) == 0) {
1176                                                                         flag = TRUE;
1177                                                                         len_cur = len_tmp;
1178                                                                         start_cur = tmp_start;
1179                                                                         break;
1180                                                                 }
1181                                                                 tmp_start += tmp_divide - tmp_start % tmp_divide;
1182                                                                 if (tmp_start >= res_cur->start - 1)
1183                                                                         break;
1184                                                         }
1185                                                 }
1186
1187                                                 if (flag && len_cur == res->len) {
1188                                                         res->start = start_cur;
1189                                                         res->len += 1; /* To restore the balance */
1190                                                         res->end = res->start + res->len - 1;
1191                                                         return 0;
1192                                                 }
1193                                         }
1194                                 }
1195                         }
1196                 }
1197                 /* end if (res_prev) */
1198                 res_prev = res_cur;
1199                 if (res_cur->next)
1200                         res_cur = res_cur->next;
1201                 else
1202                         res_cur = res_cur->nextRange;
1203         }       /* end of while */
1204
1205
1206         if (!res_prev) {
1207                 /* 1st device ever */
1208                 /* need to find appropriate range */
1209                 switch (res->type) {
1210                         case IO:
1211                                 range = bus_cur->rangeIO;
1212                                 break;
1213                         case MEM:
1214                                 range = bus_cur->rangeMem;
1215                                 break;
1216                         case PFMEM:
1217                                 range = bus_cur->rangePFMem;
1218                                 break;
1219                 }
1220                 while (range) {
1221                         if ((len_tmp = range->end - range->start) >= res->len) {
1222                                 if ((len_tmp < len_cur) || (len_cur == 0)) {
1223                                         if ((range->start % tmp_divide) == 0) {
1224                                                 /* just perfect, starting address's divisible by length */
1225                                                 flag = TRUE;
1226                                                 len_cur = len_tmp;
1227                                                 start_cur = range->start;
1228                                         } else {
1229                                                 /* Needs adjusting */
1230                                                 tmp_start = range->start;
1231                                                 flag = FALSE;
1232
1233                                                 while ((len_tmp = range->end - tmp_start) >= res->len) {
1234                                                         if ((tmp_start % tmp_divide) == 0) {
1235                                                                 flag = TRUE;
1236                                                                 len_cur = len_tmp;
1237                                                                 start_cur = tmp_start;
1238                                                                 break;
1239                                                         }
1240                                                         tmp_start += tmp_divide - tmp_start % tmp_divide;
1241                                                         if (tmp_start >= range->end)
1242                                                                 break;
1243                                                 }
1244                                         }
1245
1246                                         if (flag && len_cur == res->len) {
1247                                                 res->start = start_cur;
1248                                                 res->len += 1; /* To restore the balance */
1249                                                 res->end = res->start + res->len - 1;
1250                                                 return 0;
1251                                         }
1252                                 }
1253                         }
1254                         range = range->next;
1255                 }               /* end of while */
1256
1257                 if ((!range) && (len_cur == 0)) {
1258                         /* have gone through the list of devices and ranges and haven't found n.e.thing */
1259                         err ("no appropriate range.. bailing out...\n");
1260                         return -EINVAL;
1261                 } else if (len_cur) {
1262                         res->start = start_cur;
1263                         res->len += 1; /* To restore the balance */
1264                         res->end = res->start + res->len - 1;
1265                         return 0;
1266                 }
1267         }
1268
1269         if (!res_cur) {
1270                 debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges);
1271                 if (res_prev->rangeno < noranges) {
1272                         /* if there're more ranges out there to check */
1273                         switch (res->type) {
1274                                 case IO:
1275                                         range = bus_cur->rangeIO;
1276                                         break;
1277                                 case MEM:
1278                                         range = bus_cur->rangeMem;
1279                                         break;
1280                                 case PFMEM:
1281                                         range = bus_cur->rangePFMem;
1282                                         break;
1283                         }
1284                         while (range) {
1285                                 if ((len_tmp = range->end - range->start) >= res->len) {
1286                                         if ((len_tmp < len_cur) || (len_cur == 0)) {
1287                                                 if ((range->start % tmp_divide) == 0) {
1288                                                         /* just perfect, starting address's divisible by length */
1289                                                         flag = TRUE;
1290                                                         len_cur = len_tmp;
1291                                                         start_cur = range->start;
1292                                                 } else {
1293                                                         /* Needs adjusting */
1294                                                         tmp_start = range->start;
1295                                                         flag = FALSE;
1296
1297                                                         while ((len_tmp = range->end - tmp_start) >= res->len) {
1298                                                                 if ((tmp_start % tmp_divide) == 0) {
1299                                                                         flag = TRUE;
1300                                                                         len_cur = len_tmp;
1301                                                                         start_cur = tmp_start;
1302                                                                         break;
1303                                                                 }
1304                                                                 tmp_start += tmp_divide - tmp_start % tmp_divide;
1305                                                                 if (tmp_start >= range->end)
1306                                                                         break;
1307                                                         }
1308                                                 }
1309
1310                                                 if (flag && len_cur == res->len) {
1311                                                         res->start = start_cur;
1312                                                         res->len += 1; /* To restore the balance */
1313                                                         res->end = res->start + res->len - 1;
1314                                                         return 0;
1315                                                 }
1316                                         }
1317                                 }
1318                                 range = range->next;
1319                         }       /* end of while */
1320
1321                         if ((!range) && (len_cur == 0)) {
1322                                 /* have gone through the list of devices and ranges and haven't found n.e.thing */
1323                                 err ("no appropriate range.. bailing out...\n");
1324                                 return -EINVAL;
1325                         } else if (len_cur) {
1326                                 res->start = start_cur;
1327                                 res->len += 1; /* To restore the balance */
1328                                 res->end = res->start + res->len - 1;
1329                                 return 0;
1330                         }
1331                 } else {
1332                         /* no more ranges to check on */
1333                         if (len_cur) {
1334                                 res->start = start_cur;
1335                                 res->len += 1; /* To restore the balance */
1336                                 res->end = res->start + res->len - 1;
1337                                 return 0;
1338                         } else {
1339                                 /* have gone through the list of devices and haven't found n.e.thing */
1340                                 err ("no appropriate range.. bailing out...\n");
1341                                 return -EINVAL;
1342                         }
1343                 }
1344         }       /* end if(!res_cur) */
1345         return -EINVAL;
1346 }
1347
1348 /********************************************************************************
1349  * This routine is called from remove_card if the card contained PPB.
1350  * It will remove all the resources on the bus as well as the bus itself
1351  * Input: Bus
1352  * Ouput: 0, -ENODEV
1353  ********************************************************************************/
1354 int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno)
1355 {
1356         struct resource_node *res_cur;
1357         struct resource_node *res_tmp;
1358         struct bus_node *prev_bus;
1359         int rc;
1360
1361         prev_bus = find_bus_wprev (parent_busno, NULL, 0);      
1362
1363         if (!prev_bus) {
1364                 debug ("something terribly wrong. Cannot find parent bus to the one to remove\n");
1365                 return -ENODEV;
1366         }
1367
1368         debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno);
1369
1370         rc = remove_ranges (bus, prev_bus);
1371         if (rc)
1372                 return rc;
1373
1374         if (bus->firstIO) {
1375                 res_cur = bus->firstIO;
1376                 while (res_cur) {
1377                         res_tmp = res_cur;
1378                         if (res_cur->next)
1379                                 res_cur = res_cur->next;
1380                         else
1381                                 res_cur = res_cur->nextRange;
1382                         kfree (res_tmp);
1383                         res_tmp = NULL;
1384                 }
1385                 bus->firstIO = NULL;
1386         }
1387         if (bus->firstMem) {
1388                 res_cur = bus->firstMem;
1389                 while (res_cur) {
1390                         res_tmp = res_cur;
1391                         if (res_cur->next)
1392                                 res_cur = res_cur->next;
1393                         else
1394                                 res_cur = res_cur->nextRange;
1395                         kfree (res_tmp);
1396                         res_tmp = NULL;
1397                 }
1398                 bus->firstMem = NULL;
1399         }
1400         if (bus->firstPFMem) {
1401                 res_cur = bus->firstPFMem;
1402                 while (res_cur) {
1403                         res_tmp = res_cur;
1404                         if (res_cur->next)
1405                                 res_cur = res_cur->next;
1406                         else
1407                                 res_cur = res_cur->nextRange;
1408                         kfree (res_tmp);
1409                         res_tmp = NULL;
1410                 }
1411                 bus->firstPFMem = NULL;
1412         }
1413
1414         if (bus->firstPFMemFromMem) {
1415                 res_cur = bus->firstPFMemFromMem;
1416                 while (res_cur) {
1417                         res_tmp = res_cur;
1418                         res_cur = res_cur->next;
1419
1420                         kfree (res_tmp);
1421                         res_tmp = NULL;
1422                 }
1423                 bus->firstPFMemFromMem = NULL;
1424         }
1425
1426         list_del (&bus->bus_list);
1427         kfree (bus);
1428         return 0;
1429 }
1430
1431 /******************************************************************************
1432  * This routine deletes the ranges from a given bus, and the entries from the 
1433  * parent's bus in the resources
1434  * Input: current bus, previous bus
1435  * Output: 0, -EINVAL
1436  ******************************************************************************/
1437 static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev)
1438 {
1439         struct range_node *range_cur;
1440         struct range_node *range_tmp;
1441         int i;
1442         struct resource_node *res = NULL;
1443
1444         if (bus_cur->noIORanges) {
1445                 range_cur = bus_cur->rangeIO;
1446                 for (i = 0; i < bus_cur->noIORanges; i++) {
1447                         if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0)
1448                                 return -EINVAL;
1449                         ibmphp_remove_resource (res);
1450
1451                         range_tmp = range_cur;
1452                         range_cur = range_cur->next;
1453                         kfree (range_tmp);
1454                         range_tmp = NULL;
1455                 }
1456                 bus_cur->rangeIO = NULL;
1457         }
1458         if (bus_cur->noMemRanges) {
1459                 range_cur = bus_cur->rangeMem;
1460                 for (i = 0; i < bus_cur->noMemRanges; i++) {
1461                         if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) 
1462                                 return -EINVAL;
1463
1464                         ibmphp_remove_resource (res);
1465                         range_tmp = range_cur;
1466                         range_cur = range_cur->next;
1467                         kfree (range_tmp);
1468                         range_tmp = NULL;
1469                 }
1470                 bus_cur->rangeMem = NULL;
1471         }
1472         if (bus_cur->noPFMemRanges) {
1473                 range_cur = bus_cur->rangePFMem;
1474                 for (i = 0; i < bus_cur->noPFMemRanges; i++) {
1475                         if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) 
1476                                 return -EINVAL;
1477
1478                         ibmphp_remove_resource (res);
1479                         range_tmp = range_cur;
1480                         range_cur = range_cur->next;
1481                         kfree (range_tmp);
1482                         range_tmp = NULL;
1483                 }
1484                 bus_cur->rangePFMem = NULL;
1485         }
1486         return 0;
1487 }
1488
1489 /*
1490  * find the resource node in the bus 
1491  * Input: Resource needed, start address of the resource, type of resource
1492  */
1493 int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag)
1494 {
1495         struct resource_node *res_cur = NULL;
1496         char * type = "";
1497
1498         if (!bus) {
1499                 err ("The bus passed in NULL to find resource\n");
1500                 return -ENODEV;
1501         }
1502
1503         switch (flag) {
1504                 case IO:
1505                         res_cur = bus->firstIO;
1506                         type = "io";
1507                         break;
1508                 case MEM:
1509                         res_cur = bus->firstMem;
1510                         type = "mem";
1511                         break;
1512                 case PFMEM:
1513                         res_cur = bus->firstPFMem;
1514                         type = "pfmem";
1515                         break;
1516                 default:
1517                         err ("wrong type of flag\n");
1518                         return -EINVAL;
1519         }
1520         
1521         while (res_cur) {
1522                 if (res_cur->start == start_address) {
1523                         *res = res_cur;
1524                         break;
1525                 }
1526                 if (res_cur->next)
1527                         res_cur = res_cur->next;
1528                 else
1529                         res_cur = res_cur->nextRange;
1530         }
1531
1532         if (!res_cur) {
1533                 if (flag == PFMEM) {
1534                         res_cur = bus->firstPFMemFromMem;
1535                         while (res_cur) {
1536                                 if (res_cur->start == start_address) {
1537                                         *res = res_cur;
1538                                         break;
1539                                 }
1540                                 res_cur = res_cur->next;
1541                         }
1542                         if (!res_cur) {
1543                                 debug ("SOS...cannot find %s resource in the bus.\n", type);
1544                                 return -EINVAL;
1545                         }
1546                 } else {
1547                         debug ("SOS... cannot find %s resource in the bus.\n", type);
1548                         return -EINVAL;
1549                 }
1550         }
1551
1552         if (*res)
1553                 debug ("*res->start = %x\n", (*res)->start);
1554
1555         return 0;
1556 }
1557
1558 /***********************************************************************
1559  * This routine will free the resource structures used by the
1560  * system.  It is called from cleanup routine for the module
1561  * Parameters: none
1562  * Returns: none
1563  ***********************************************************************/
1564 void ibmphp_free_resources (void)
1565 {
1566         struct bus_node *bus_cur = NULL;
1567         struct bus_node *bus_tmp;
1568         struct range_node *range_cur;
1569         struct range_node *range_tmp;
1570         struct resource_node *res_cur;
1571         struct resource_node *res_tmp;
1572         struct list_head *tmp;
1573         struct list_head *next;
1574         int i = 0;
1575         flags = 1;
1576
1577         list_for_each_safe (tmp, next, &gbuses) {
1578                 bus_cur = list_entry (tmp, struct bus_node, bus_list);
1579                 if (bus_cur->noIORanges) {
1580                         range_cur = bus_cur->rangeIO;
1581                         for (i = 0; i < bus_cur->noIORanges; i++) {
1582                                 if (!range_cur)
1583                                         break;
1584                                 range_tmp = range_cur;
1585                                 range_cur = range_cur->next;
1586                                 kfree (range_tmp);
1587                                 range_tmp = NULL;
1588                         }
1589                 }
1590                 if (bus_cur->noMemRanges) {
1591                         range_cur = bus_cur->rangeMem;
1592                         for (i = 0; i < bus_cur->noMemRanges; i++) {
1593                                 if (!range_cur)
1594                                         break;
1595                                 range_tmp = range_cur;
1596                                 range_cur = range_cur->next;
1597                                 kfree (range_tmp);
1598                                 range_tmp = NULL;
1599                         }
1600                 }
1601                 if (bus_cur->noPFMemRanges) {
1602                         range_cur = bus_cur->rangePFMem;
1603                         for (i = 0; i < bus_cur->noPFMemRanges; i++) {
1604                                 if (!range_cur)
1605                                         break;
1606                                 range_tmp = range_cur;
1607                                 range_cur = range_cur->next;
1608                                 kfree (range_tmp);
1609                                 range_tmp = NULL;
1610                         }
1611                 }
1612
1613                 if (bus_cur->firstIO) {
1614                         res_cur = bus_cur->firstIO;
1615                         while (res_cur) {
1616                                 res_tmp = res_cur;
1617                                 if (res_cur->next)
1618                                         res_cur = res_cur->next;
1619                                 else
1620                                         res_cur = res_cur->nextRange;
1621                                 kfree (res_tmp);
1622                                 res_tmp = NULL;
1623                         }
1624                         bus_cur->firstIO = NULL;
1625                 }
1626                 if (bus_cur->firstMem) {
1627                         res_cur = bus_cur->firstMem;
1628                         while (res_cur) {
1629                                 res_tmp = res_cur;
1630                                 if (res_cur->next)
1631                                         res_cur = res_cur->next;
1632                                 else
1633                                         res_cur = res_cur->nextRange;
1634                                 kfree (res_tmp);
1635                                 res_tmp = NULL;
1636                         }
1637                         bus_cur->firstMem = NULL;
1638                 }
1639                 if (bus_cur->firstPFMem) {
1640                         res_cur = bus_cur->firstPFMem;
1641                         while (res_cur) {
1642                                 res_tmp = res_cur;
1643                                 if (res_cur->next)
1644                                         res_cur = res_cur->next;
1645                                 else
1646                                         res_cur = res_cur->nextRange;
1647                                 kfree (res_tmp);
1648                                 res_tmp = NULL;
1649                         }
1650                         bus_cur->firstPFMem = NULL;
1651                 }
1652
1653                 if (bus_cur->firstPFMemFromMem) {
1654                         res_cur = bus_cur->firstPFMemFromMem;
1655                         while (res_cur) {
1656                                 res_tmp = res_cur;
1657                                 res_cur = res_cur->next;
1658
1659                                 kfree (res_tmp);
1660                                 res_tmp = NULL;
1661                         }
1662                         bus_cur->firstPFMemFromMem = NULL;
1663                 }
1664
1665                 bus_tmp = bus_cur;
1666                 list_del (&bus_cur->bus_list);
1667                 kfree (bus_tmp);
1668                 bus_tmp = NULL;
1669         }
1670 }
1671
1672 /*********************************************************************************
1673  * This function will go over the PFmem resources to check if the EBDA allocated
1674  * pfmem out of memory buckets of the bus.  If so, it will change the range numbers
1675  * and a flag to indicate that this resource is out of memory. It will also move the
1676  * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create
1677  * a new Mem node
1678  * This routine is called right after initialization
1679  *******************************************************************************/
1680 static int __init once_over (void)
1681 {
1682         struct resource_node *pfmem_cur;
1683         struct resource_node *pfmem_prev;
1684         struct resource_node *mem;
1685         struct bus_node *bus_cur;
1686         struct list_head *tmp;
1687
1688         list_for_each (tmp, &gbuses) {
1689                 bus_cur = list_entry (tmp, struct bus_node, bus_list);
1690                 if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) {
1691                         for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) {
1692                                 pfmem_cur->fromMem = TRUE;
1693                                 if (pfmem_prev)
1694                                         pfmem_prev->next = pfmem_cur->next;
1695                                 else
1696                                         bus_cur->firstPFMem = pfmem_cur->next;
1697
1698                                 if (!bus_cur->firstPFMemFromMem)
1699                                         pfmem_cur->next = NULL;
1700                                 else
1701                                         /* we don't need to sort PFMemFromMem since we're using mem node for
1702                                            all the real work anyways, so just insert at the beginning of the
1703                                            list
1704                                          */
1705                                         pfmem_cur->next = bus_cur->firstPFMemFromMem;
1706
1707                                 bus_cur->firstPFMemFromMem = pfmem_cur;
1708
1709                                 mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);              
1710                                 if (!mem) {
1711                                         err ("out of system memory\n");
1712                                         return -ENOMEM;
1713                                 }
1714                                 memset (mem, 0, sizeof (struct resource_node));
1715                                 mem->type = MEM;
1716                                 mem->busno = pfmem_cur->busno;
1717                                 mem->devfunc = pfmem_cur->devfunc;
1718                                 mem->start = pfmem_cur->start;
1719                                 mem->end = pfmem_cur->end;
1720                                 mem->len = pfmem_cur->len;
1721                                 if (ibmphp_add_resource (mem) < 0)
1722                                         err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n");
1723                                 pfmem_cur->rangeno = mem->rangeno;
1724                         }       /* end for pfmem */
1725                 }       /* end if */
1726         }       /* end list_for_each bus */
1727         return 0; 
1728 }
1729
1730 int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem)
1731 {
1732         struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0);
1733
1734         if (!bus_cur) {
1735                 err ("cannot find bus of pfmem to add...\n");
1736                 return -ENODEV;
1737         }
1738
1739         if (bus_cur->firstPFMemFromMem)
1740                 pfmem->next = bus_cur->firstPFMemFromMem;
1741         else
1742                 pfmem->next = NULL;
1743
1744         bus_cur->firstPFMemFromMem = pfmem;
1745
1746         return 0;
1747 }
1748
1749 /* This routine just goes through the buses to see if the bus already exists.
1750  * It is called from ibmphp_find_sec_number, to find out a secondary bus number for
1751  * bridged cards
1752  * Parameters: bus_number
1753  * Returns: Bus pointer or NULL
1754  */
1755 struct bus_node *ibmphp_find_res_bus (u8 bus_number)
1756 {
1757         return find_bus_wprev (bus_number, NULL, 0);
1758 }
1759
1760 static struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag)
1761 {
1762         struct bus_node *bus_cur;
1763         struct list_head *tmp;
1764         struct list_head *tmp_prev;
1765
1766         list_for_each (tmp, &gbuses) {
1767                 tmp_prev = tmp->prev;
1768                 bus_cur = list_entry (tmp, struct bus_node, bus_list);
1769                 if (flag) 
1770                         *prev = list_entry (tmp_prev, struct bus_node, bus_list);
1771                 if (bus_cur->busno == bus_number) 
1772                         return bus_cur;
1773         }
1774
1775         return NULL;
1776 }
1777
1778 void ibmphp_print_test (void)
1779 {
1780         int i = 0;
1781         struct bus_node *bus_cur = NULL;
1782         struct range_node *range;
1783         struct resource_node *res;
1784         struct list_head *tmp;
1785         
1786         debug_pci ("*****************START**********************\n");
1787
1788         if ((!list_empty(&gbuses)) && flags) {
1789                 err ("The GBUSES is not NULL?!?!?!?!?\n");
1790                 return;
1791         }
1792
1793         list_for_each (tmp, &gbuses) {
1794                 bus_cur = list_entry (tmp, struct bus_node, bus_list);
1795                 debug_pci ("This is bus # %d.  There are\n", bus_cur->busno);
1796                 debug_pci ("IORanges = %d\t", bus_cur->noIORanges);
1797                 debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges);
1798                 debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges);
1799                 debug_pci ("The IO Ranges are as follows:\n");
1800                 if (bus_cur->rangeIO) {
1801                         range = bus_cur->rangeIO;
1802                         for (i = 0; i < bus_cur->noIORanges; i++) {
1803                                 debug_pci ("rangeno is %d\n", range->rangeno);
1804                                 debug_pci ("[%x - %x]\n", range->start, range->end);
1805                                 range = range->next;
1806                         }
1807                 }
1808
1809                 debug_pci ("The Mem Ranges are as follows:\n");
1810                 if (bus_cur->rangeMem) {
1811                         range = bus_cur->rangeMem;
1812                         for (i = 0; i < bus_cur->noMemRanges; i++) {
1813                                 debug_pci ("rangeno is %d\n", range->rangeno);
1814                                 debug_pci ("[%x - %x]\n", range->start, range->end);
1815                                 range = range->next;
1816                         }
1817                 }
1818
1819                 debug_pci ("The PFMem Ranges are as follows:\n");
1820
1821                 if (bus_cur->rangePFMem) {
1822                         range = bus_cur->rangePFMem;
1823                         for (i = 0; i < bus_cur->noPFMemRanges; i++) {
1824                                 debug_pci ("rangeno is %d\n", range->rangeno);
1825                                 debug_pci ("[%x - %x]\n", range->start, range->end);
1826                                 range = range->next;
1827                         }
1828                 }
1829
1830                 debug_pci ("The resources on this bus are as follows\n");
1831
1832                 debug_pci ("IO...\n");
1833                 if (bus_cur->firstIO) {
1834                         res = bus_cur->firstIO;
1835                         while (res) {
1836                                 debug_pci ("The range # is %d\n", res->rangeno);
1837                                 debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
1838                                 debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
1839                                 if (res->next)
1840                                         res = res->next;
1841                                 else if (res->nextRange)
1842                                         res = res->nextRange;
1843                                 else
1844                                         break;
1845                         }
1846                 }
1847                 debug_pci ("Mem...\n");
1848                 if (bus_cur->firstMem) {
1849                         res = bus_cur->firstMem;
1850                         while (res) {
1851                                 debug_pci ("The range # is %d\n", res->rangeno);
1852                                 debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
1853                                 debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
1854                                 if (res->next)
1855                                         res = res->next;
1856                                 else if (res->nextRange)
1857                                         res = res->nextRange;
1858                                 else
1859                                         break;
1860                         }
1861                 }
1862                 debug_pci ("PFMem...\n");
1863                 if (bus_cur->firstPFMem) {
1864                         res = bus_cur->firstPFMem;
1865                         while (res) {
1866                                 debug_pci ("The range # is %d\n", res->rangeno);
1867                                 debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
1868                                 debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
1869                                 if (res->next)
1870                                         res = res->next;
1871                                 else if (res->nextRange)
1872                                         res = res->nextRange;
1873                                 else
1874                                         break;
1875                         }
1876                 }
1877
1878                 debug_pci ("PFMemFromMem...\n");
1879                 if (bus_cur->firstPFMemFromMem) {
1880                         res = bus_cur->firstPFMemFromMem;
1881                         while (res) {
1882                                 debug_pci ("The range # is %d\n", res->rangeno);
1883                                 debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc);
1884                                 debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len);
1885                                 res = res->next;
1886                         }
1887                 }
1888         }
1889         debug_pci ("***********************END***********************\n");
1890 }
1891
1892 static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type)
1893 {
1894         struct range_node * range_cur = NULL;
1895         switch (type) {
1896                 case IO:
1897                         range_cur = bus_cur->rangeIO;
1898                         break;
1899                 case MEM:
1900                         range_cur = bus_cur->rangeMem;
1901                         break;
1902                 case PFMEM:
1903                         range_cur = bus_cur->rangePFMem;
1904                         break;
1905                 default:
1906                         err ("wrong type passed to find out if range already exists\n");
1907                         return -ENODEV;
1908         }
1909
1910         while (range_cur) {
1911                 if ((range_cur->start == range->start) && (range_cur->end == range->end))
1912                         return 1;
1913                 range_cur = range_cur->next;
1914         }
1915         
1916         return 0;
1917 }
1918
1919 /* This routine will read the windows for any PPB we have and update the
1920  * range info for the secondary bus, and will also input this info into
1921  * primary bus, since BIOS doesn't. This is for PPB that are in the system
1922  * on bootup.  For bridged cards that were added during previous load of the
1923  * driver, only the ranges and the bus structure are added, the devices are
1924  * added from NVRAM
1925  * Input: primary busno
1926  * Returns: none
1927  * Note: this function doesn't take into account IO restrictions etc,
1928  *       so will only work for bridges with no video/ISA devices behind them It
1929  *       also will not work for onboard PPB's that can have more than 1 *bus
1930  *       behind them All these are TO DO.
1931  *       Also need to add more error checkings... (from fnc returns etc)
1932  */
1933 static int __init update_bridge_ranges (struct bus_node **bus)
1934 {
1935         u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address;
1936         u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
1937         u32 start_address, end_address, upper_start, upper_end;
1938         struct bus_node *bus_sec;
1939         struct bus_node *bus_cur;
1940         struct resource_node *io;
1941         struct resource_node *mem;
1942         struct resource_node *pfmem;
1943         struct range_node *range;
1944         unsigned int devfn;
1945
1946         bus_cur = *bus;
1947         if (!bus_cur)
1948                 return -ENODEV;
1949         ibmphp_pci_bus->number = bus_cur->busno;
1950
1951         debug ("inside %s\n", __FUNCTION__);
1952         debug ("bus_cur->busno = %x\n", bus_cur->busno);
1953
1954         for (device = 0; device < 32; device++) {
1955                 for (function = 0x00; function < 0x08; function++) {
1956                         devfn = PCI_DEVFN(device, function);
1957                         pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id);
1958
1959                         if (vendor_id != PCI_VENDOR_ID_NOTVALID) {
1960                                 /* found correct device!!! */
1961                                 pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type);
1962
1963                                 switch (hdr_type) {
1964                                         case PCI_HEADER_TYPE_NORMAL:
1965                                                 function = 0x8;
1966                                                 break;
1967                                         case PCI_HEADER_TYPE_MULTIDEVICE:
1968                                                 break;
1969                                         case PCI_HEADER_TYPE_BRIDGE:
1970                                                 function = 0x8;
1971                                         case PCI_HEADER_TYPE_MULTIBRIDGE:
1972                                                 /* We assume here that only 1 bus behind the bridge 
1973                                                    TO DO: add functionality for several:
1974                                                    temp = secondary;
1975                                                    while (temp < subordinate) {
1976                                                    ...
1977                                                    temp++;
1978                                                    }
1979                                                  */
1980                                                 pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno);
1981                                                 bus_sec = find_bus_wprev (sec_busno, NULL, 0); 
1982                                                 /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */
1983                                                 if (!bus_sec) {
1984                                                         bus_sec = alloc_error_bus (NULL, sec_busno, 1);
1985                                                         /* the rest will be populated during NVRAM call */
1986                                                         return 0;
1987                                                 }
1988                                                 pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address);
1989                                                 pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address);
1990                                                 pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start);
1991                                                 pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end);
1992                                                 start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8;
1993                                                 start_address |= (upper_io_start << 16);
1994                                                 end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8;
1995                                                 end_address |= (upper_io_end << 16);
1996
1997                                                 if ((start_address) && (start_address <= end_address)) {
1998                                                         range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
1999                                                         if (!range) {
2000                                                                 err ("out of system memory\n");
2001                                                                 return -ENOMEM;
2002                                                         }
2003                                                         memset (range, 0, sizeof (struct range_node));
2004                                                         range->start = start_address;
2005                                                         range->end = end_address + 0xfff;
2006
2007                                                         if (bus_sec->noIORanges > 0) {
2008                                                                 if (!range_exists_already (range, bus_sec, IO)) {
2009                                                                         add_range (IO, range, bus_sec);
2010                                                                         ++bus_sec->noIORanges;
2011                                                                 } else {
2012                                                                         kfree (range);
2013                                                                         range = NULL;
2014                                                                 }
2015                                                         } else {
2016                                                                 /* 1st IO Range on the bus */
2017                                                                 range->rangeno = 1;
2018                                                                 bus_sec->rangeIO = range;
2019                                                                 ++bus_sec->noIORanges;
2020                                                         }
2021                                                         fix_resources (bus_sec);
2022
2023                                                         if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) {
2024                                                                 io = kmalloc (sizeof (struct resource_node), GFP_KERNEL);                                                       
2025                                                                 if (!io) {
2026                                                                         kfree (range);
2027                                                                         err ("out of system memory\n");
2028                                                                         return -ENOMEM;
2029                                                                 }
2030                                                                 memset (io, 0, sizeof (struct resource_node));
2031                                                                 io->type = IO;
2032                                                                 io->busno = bus_cur->busno;
2033                                                                 io->devfunc = ((device << 3) | (function & 0x7));
2034                                                                 io->start = start_address;
2035                                                                 io->end = end_address + 0xfff;
2036                                                                 io->len = io->end - io->start + 1;
2037                                                                 ibmphp_add_resource (io);
2038                                                         }
2039                                                 }       
2040
2041                                                 pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address);
2042                                                 pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address);
2043
2044                                                 start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
2045                                                 end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
2046
2047                                                 if ((start_address) && (start_address <= end_address)) {
2048
2049                                                         range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
2050                                                         if (!range) {
2051                                                                 err ("out of system memory\n");
2052                                                                 return -ENOMEM;
2053                                                         }
2054                                                         memset (range, 0, sizeof (struct range_node));
2055                                                         range->start = start_address;
2056                                                         range->end = end_address + 0xfffff;
2057
2058                                                         if (bus_sec->noMemRanges > 0) {
2059                                                                 if (!range_exists_already (range, bus_sec, MEM)) {
2060                                                                         add_range (MEM, range, bus_sec);
2061                                                                         ++bus_sec->noMemRanges;
2062                                                                 } else {
2063                                                                         kfree (range);
2064                                                                         range = NULL;
2065                                                                 }
2066                                                         } else {
2067                                                                 /* 1st Mem Range on the bus */
2068                                                                 range->rangeno = 1;
2069                                                                 bus_sec->rangeMem = range;
2070                                                                 ++bus_sec->noMemRanges;
2071                                                         }
2072
2073                                                         fix_resources (bus_sec);
2074
2075                                                         if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) {
2076                                                                 mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
2077                                                                 if (!mem) {
2078                                                                         kfree (range);
2079                                                                         err ("out of system memory\n");
2080                                                                         return -ENOMEM;
2081                                                                 }
2082                                                                 memset (mem, 0, sizeof (struct resource_node));
2083                                                                 mem->type = MEM;
2084                                                                 mem->busno = bus_cur->busno;
2085                                                                 mem->devfunc = ((device << 3) | (function & 0x7));
2086                                                                 mem->start = start_address;
2087                                                                 mem->end = end_address + 0xfffff;
2088                                                                 mem->len = mem->end - mem->start + 1;
2089                                                                 ibmphp_add_resource (mem);
2090                                                         }
2091                                                 }
2092                                                 pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address);
2093                                                 pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address);
2094                                                 pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start);
2095                                                 pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end);
2096                                                 start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
2097                                                 end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16;
2098 #if BITS_PER_LONG == 64
2099                                                 start_address |= ((long) upper_start) << 32;
2100                                                 end_address |= ((long) upper_end) << 32;
2101 #endif
2102
2103                                                 if ((start_address) && (start_address <= end_address)) {
2104
2105                                                         range = kmalloc (sizeof (struct range_node), GFP_KERNEL);
2106                                                         if (!range) {
2107                                                                 err ("out of system memory\n");
2108                                                                 return -ENOMEM;
2109                                                         }
2110                                                         memset (range, 0, sizeof (struct range_node));
2111                                                         range->start = start_address;
2112                                                         range->end = end_address + 0xfffff;
2113
2114                                                         if (bus_sec->noPFMemRanges > 0) {
2115                                                                 if (!range_exists_already (range, bus_sec, PFMEM)) {
2116                                                                         add_range (PFMEM, range, bus_sec);
2117                                                                         ++bus_sec->noPFMemRanges;
2118                                                                 } else {
2119                                                                         kfree (range);
2120                                                                         range = NULL;
2121                                                                 }
2122                                                         } else {
2123                                                                 /* 1st PFMem Range on the bus */
2124                                                                 range->rangeno = 1;
2125                                                                 bus_sec->rangePFMem = range;
2126                                                                 ++bus_sec->noPFMemRanges;
2127                                                         }
2128
2129                                                         fix_resources (bus_sec);
2130                                                         if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) {
2131                                                                 pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
2132                                                                 if (!pfmem) {
2133                                                                         kfree (range);
2134                                                                         err ("out of system memory\n");
2135                                                                         return -ENOMEM;
2136                                                                 }
2137                                                                 memset (pfmem, 0, sizeof (struct resource_node));
2138                                                                 pfmem->type = PFMEM;
2139                                                                 pfmem->busno = bus_cur->busno;
2140                                                                 pfmem->devfunc = ((device << 3) | (function & 0x7));
2141                                                                 pfmem->start = start_address;
2142                                                                 pfmem->end = end_address + 0xfffff;
2143                                                                 pfmem->len = pfmem->end - pfmem->start + 1;
2144                                                                 pfmem->fromMem = FALSE;
2145
2146                                                                 ibmphp_add_resource (pfmem);
2147                                                         }
2148                                                 }
2149                                                 break;
2150                                 }       /* end of switch */
2151                         }       /* end if vendor */
2152                 }       /* end for function */
2153         }       /* end for device */
2154
2155         bus = &bus_cur;
2156         return 0;
2157 }