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