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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [pci/] [hotplug/] [ibmphp_res.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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