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