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