root/drivers/pci/hotplug/ibmphp_res.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. alloc_error_bus
  2. alloc_resources
  3. alloc_bus_range
  4. ibmphp_rsrc_init
  5. add_bus_range
  6. update_resources
  7. fix_me
  8. fix_resources
  9. ibmphp_add_resource
  10. ibmphp_remove_resource
  11. find_range
  12. ibmphp_check_resource
  13. ibmphp_remove_bus
  14. remove_ranges
  15. ibmphp_find_resource
  16. ibmphp_free_resources
  17. once_over
  18. ibmphp_add_pfmem_from_mem
  19. ibmphp_find_res_bus
  20. find_bus_wprev
  21. ibmphp_print_test
  22. range_exists_already
  23. update_bridge_ranges

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

/* [<][>][^][v][top][bottom][index][help] */