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