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