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