OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [hotplug/] [ibmphp_res.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
 
37
static int flags = 0;            /* for testing */
38
 
39
static void update_resources (struct bus_node *bus_cur, int type, int rangeno);
40
static int once_over (void);
41
static int remove_ranges (struct bus_node *, struct bus_node *);
42
static int update_bridge_ranges (struct bus_node **);
43
static int add_range (int type, struct range_node *, struct bus_node *);
44
static void fix_resources (struct bus_node *);
45
static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8);
46
 
47
static LIST_HEAD(gbuses);
48
LIST_HEAD(ibmphp_res_head);
49
 
50
static 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
 
74
static 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
 
97
static 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
 ***************************************************************************/
204
int __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
 ********************************************************************************/
392
static 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
 ******************************************************************************/
467
static 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
 
511
static 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
 *******************************************************************************/
566
static 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
 *******************************************************************************/
599
int 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
 ****************************************************************************/
781
int 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
 
942
static 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
 *****************************************************************************/
977
int 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
 ********************************************************************************/
1354
int 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
 ******************************************************************************/
1437
static 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
 */
1493
int 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
 ***********************************************************************/
1564
void 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
 *******************************************************************************/
1680
static 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
 
1730
int 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
 */
1755
struct bus_node *ibmphp_find_res_bus (u8 bus_number)
1756
{
1757
        return find_bus_wprev (bus_number, NULL, 0);
1758
}
1759
 
1760
static inline 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
 
1778
void 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
 
1892
int 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
 */
1933
static 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.