source: rtems/cpukit/libpci/pci_cfg_auto.c @ 0decc806

4.115
Last change on this file since 0decc806 was f4bf22c, checked in by Daniel Hellstrom <daniel@…>, on 04/08/15 at 08:51:45

LIBPCI: new implementation private header file

  • new implementation private header file
  • moved double implementation of pci_dev_create used by read & auto cfg libraries to common pci_dev_create.c
  • moved declaration of pci_bus_cnt to private header file so avoid extern in .c files
  • Property mode set to 100644
File size: 26.4 KB
Line 
1/*  PCI (Auto) configuration Library. Setup PCI configuration space and IRQ.
2 *
3 *  COPYRIGHT (c) 2010 Cobham Gaisler AB.
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 */
9
10#include <rtems.h>
11#include <stdlib.h>
12#include <rtems/bspIo.h>
13#include <string.h>
14
15/* Configure headers */
16#define PCI_CFG_AUTO_LIB
17
18#include <pci.h>
19#include <pci/access.h>
20#include <pci/cfg.h>
21
22#include "pci_internal.h"
23
24/* #define DEBUG */
25
26#ifdef DEBUG
27#define DBG(x...) printk(x)
28#else
29#define DBG(x...)
30#endif
31
32/* PCI Library
33 * (For debugging it might be good to use other functions or the driver's
34 *  directly)
35 */
36#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
37#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
38#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
39#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
40#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
41#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
42
43int pci_config_auto_initialized = 0;
44
45/* Configuration setup */
46struct pci_auto_setup pci_auto_cfg;
47
48/* Insert BAR into the sorted resources list. The BARs are sorted on the
49 * BAR size/alignment need.
50 */
51static void pci_res_insert(struct pci_res **root, struct pci_res *res)
52{
53        struct pci_res *curr, *last;
54        unsigned long curr_size_resulting_boundary, size_resulting_boundary;
55        unsigned long boundary, size;
56
57        res->start = 0;
58        res->end = 0;
59        boundary = res->boundary;
60        size = res->size;
61
62        /* Insert the resources depending on the boundary needs
63         * Normally the boundary=size of the BAR, however when
64         * PCI bridges are involved the bridge's boundary may be
65         * smaller than the size due to the fact that a bridge
66         * may have different-sized BARs behind, the largest BAR
67         * (also the BAR with the largest boundary) will decide
68         * the alignment need.
69         */
70        last = NULL;
71        curr = *root;
72
73        /* Order List after boundary, the boundary is maintained
74         * when the size is on an equal boundary, normally it is
75         * but may not be with bridges. So in second hand it is
76         * sorted after resulting boundary - the boundary after
77         * the resource.
78         */
79        while (curr && (curr->boundary >= boundary)) {
80                if (curr->boundary == boundary) {
81                        /* Find Resulting boundary of size */
82                        size_resulting_boundary = 1;
83                        while ((size & size_resulting_boundary) == 0)
84                                size_resulting_boundary =
85                                        size_resulting_boundary << 1;
86
87                        /* Find Resulting boundary of curr->size */
88                        curr_size_resulting_boundary = 1;
89                        while ((curr->size & curr_size_resulting_boundary) == 0)
90                                curr_size_resulting_boundary =
91                                        curr_size_resulting_boundary << 1;
92
93                        if (size_resulting_boundary >=
94                            curr_size_resulting_boundary)
95                                break;
96                }
97                last = curr;
98                curr = curr->next;
99        }
100
101        if (last == NULL) {
102                /* Insert first in list */
103                res->next = *root;
104                *root = res;
105        } else {
106                last->next = res;
107                res->next = curr;
108        }
109}
110
111#ifdef DEBUG
112void pci_res_list_print(struct pci_res *root)
113{
114        if (root == NULL)
115                return;
116
117        printf("RESOURCE LIST:\n");
118        while (root) {
119                printf(" SIZE: 0x%08x, BOUNDARY: 0x%08x\n", root->size,
120                                                                root->boundary);
121                root = root->next;
122        }
123}
124#endif
125
126/* Reorder a size/alignment ordered resources list. The idea is to
127 * avoid unused due to alignment/size restriction.
128 *
129 * NOTE: The first element is always untouched.
130 * NOTE: If less than three elements in list, nothing will be done
131 *
132 * Normally a BAR has the same alignment requirements as the size of the
133 * BAR. However, when bridges are involved the alignment need may be smaller
134 * than the size, because a bridge resource consist or multiple BARs.
135 * For example, say that a bridge with a 256Mb and a 16Mb BAR is found, then
136 * the alignment is required to be 256Mb but the size 256+16Mb.
137 *
138 * In order to minimize dead space on the bus, the boundary ordered list
139 * is reordered, example:
140 *  BUS0
141 *  |            BUS1
142 *  |------------|
143 *  |            |-- BAR0: SIZE=256Mb, ALIGNMENT=256MB
144 *  |            |-- BAR1: SIZE=16Mb, ALIGNMENT=16MB
145 *  |            |
146 *  |            |
147 *  |            |
148 *  |            |          BUS2 (BAR_BRIDGE1: SIZE=256+16, ALIGNEMENT=256)
149 *  |            |----------|
150 *  |            |          |-- BAR2: SIZE=256Mb, ALIGNMENT=256Mb
151 *  |            |          |-- BAR3: SIZE=16Mb, ALIGNMENT=16MB
152 *
153 * A alignment/boundary ordered list of BUS1 will look like:
154 *      - BAR_BRIDGE1
155 *      - BAR0            (ALIGMENT NEED 256Mb)
156 *      - BAR1
157 *
158 * However, Between BAR_BRIDGE1 and BAR0 will be a unused hole of 256-16Mb.
159 * We can put BAR1 before BAR0 to avoid the problem.
160 */
161static void pci_res_reorder(struct pci_res *root)
162{
163        struct pci_res *curr, *last, *curr2, *last2;
164        unsigned int start, start_next, hole_size, hole_boundary;
165
166        if (root == NULL)
167                return;
168
169        /* Make up a start address with the boundary of the
170         * First element.
171         */
172        start = root->boundary + root->size;
173        last = root;
174        curr = root->next;
175        while (curr) {
176
177                /* Find start address of resource */
178                start_next = (start + (curr->boundary - 1)) &
179                                        ~(curr->boundary - 1);
180
181                /* Find hole size, the unsed space in between last resource
182                 * and next */
183                hole_size = start_next - start;
184
185                /* Find Boundary of START */
186                hole_boundary = 1;
187                while ((start & hole_boundary) == 0)
188                        hole_boundary = hole_boundary<<1;
189
190                /* Detect dead hole */
191                if (hole_size > 0) {
192                        /* Step through list and try to find a resource that
193                         * can fit into hole. Take into account hole start
194                         * boundary and hole size.
195                         */
196                        last2 = curr;
197                        curr2 = curr->next;
198                        while (curr2) {
199                                if ((curr2->boundary <= hole_boundary) &&
200                                         (curr2->size <= hole_size)) {
201                                        /* Found matching resource. Move it
202                                         * first in the hole. Then rescan, now
203                                         * that the hole has changed in
204                                         * size/boundary.
205                                         */
206                                        last2->next = curr2->next;
207                                        curr2->next = curr;
208                                        last->next = curr2;
209
210                                        /* New Start address */
211                                        start_next = (start +
212                                                     (curr2->boundary - 1)) &
213                                                     ~(curr2->boundary - 1);
214                                        /* Since we inserted the resource before
215                                         * curr we need to re-evaluate curr one
216                                         * more, more resources may fit into the
217                                         * shrunken hole.
218                                         */
219                                        curr = curr2;
220                                        break;
221                                }
222                                last2 = curr2;
223                                curr2 = curr2->next;
224                        }
225                }
226
227                /* No hole or nothing fit into hole. */
228                start = start_next;
229
230                last = curr;
231                curr = curr->next;
232        }
233}
234
235/* Find the total size required in PCI address space needed by a resource list*/
236static unsigned int pci_res_size(struct pci_res *root)
237{
238        struct pci_res *curr;
239        unsigned int size;
240
241        /* Get total size of all resources */
242        size = 0;
243        curr = root;
244        while (curr) {
245                size = (size + (curr->boundary - 1)) & ~(curr->boundary - 1);
246                size += curr->size;
247                curr = curr->next;
248        }
249
250        return size;
251}
252
253#if 0 /* not used for now */
254/* Free a device and secondary bus if device is a bridge */
255static void pci_dev_free(struct pci_dev *dev)
256{
257        struct pci_dev *subdev;
258        struct pci_bus *bus;
259
260        if (dev->flags & PCI_DEV_BRIDGE) {
261                bus = (struct pci_bus *)dev;
262                for (subdev = bus->devs; subdev ; subdev = subdev->next)
263                        pci_dev_free(dev);
264        }
265
266        free(dev);
267}
268#endif
269
270static void pci_find_devs(struct pci_bus *bus)
271{
272        uint32_t id, tmp;
273        uint8_t header;
274        int slot, func, fail;
275        struct pci_dev *dev, **listptr;
276        struct pci_bus *bridge;
277        pci_dev_t pcidev;
278
279        DBG("Scanning bus %d\n", bus->num);
280
281        listptr = &bus->devs;
282        for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
283
284                /* Slot address */
285                pcidev = PCI_DEV(bus->num, slot, 0);
286
287                for (func = 0; func <= PCI_FUNCMAX; func++, pcidev++) {
288
289                        fail = PCI_CFG_R32(pcidev, PCIR_VENDOR, &id);
290                        if (fail || id == 0xffffffff || id == 0) {
291                                /*
292                                 * This slot is empty
293                                 */
294                                if (func == 0)
295                                        break;
296                                else
297                                        continue;
298                        }
299
300                        DBG("Found PCIDEV 0x%x at (bus %x, slot %x, func %x)\n",
301                                                        id, bus, slot, func);
302
303                        /* Set command to reset values, it disables bus
304                         * mastering and address responses.
305                         */
306                        PCI_CFG_W16(pcidev, PCIR_COMMAND, 0);
307
308                        /* Clear any already set status bits */
309                        PCI_CFG_W16(pcidev, PCIR_STATUS, 0xf900);
310
311                        /* Set latency timer to 64 */
312                        PCI_CFG_W8(pcidev, PCIR_LATTIMER, 64);
313
314                        PCI_CFG_R32(pcidev, PCIR_REVID, &tmp);
315                        tmp >>= 16;
316                        dev = pci_dev_create(tmp == PCID_PCI2PCI_BRIDGE);
317                        *listptr = dev;
318                        listptr = &dev->next;
319
320                        dev->busdevfun = pcidev;
321                        dev->bus = bus;
322                        PCI_CFG_R16(pcidev, PCIR_VENDOR, &dev->vendor);
323                        PCI_CFG_R16(pcidev, PCIR_DEVICE, &dev->device);
324                        PCI_CFG_R32(pcidev, PCIR_REVID, &dev->classrev);
325
326                        if (tmp == PCID_PCI2PCI_BRIDGE) {
327                                DBG("Found PCI-PCI Bridge 0x%x at "
328                                    "(bus %x, slot %x, func %x)\n",
329                                    id, bus, slot, func);
330                                dev->flags = PCI_DEV_BRIDGE;
331                                dev->subvendor = 0;
332                                dev->subdevice = 0;
333                                bridge = (struct pci_bus *)dev;
334                                bridge->num = bus->sord + 1;
335                                bridge->pri = bus->num;
336                                bridge->sord = bus->sord + 1;
337
338                                /* Configure bridge (no support for 64-bit) */
339                                PCI_CFG_W32(pcidev, 0x28, 0);
340                                PCI_CFG_W32(pcidev, 0x2C, 0);
341                                tmp = (64 << 24) | (0xff << 16) |
342                                      (bridge->num << 8) | bridge->pri;
343                                PCI_CFG_W32(pcidev, PCIR_PRIBUS_1, tmp);
344
345                                /* Scan Secondary Bus */
346                                pci_find_devs(bridge);
347
348                                /* sord might have been updated */
349                                PCI_CFG_W8(pcidev, 0x1a, bridge->sord);
350                                bus->sord = bridge->sord;
351
352                                DBG("PCI-PCI BRIDGE: Primary %x, Secondary %x, "
353                                    "Subordinate %x\n",
354                                    bridge->pri, bridge->num, bridge->sord);
355                        } else {
356                                /* Disable Cardbus CIS Pointer */
357                                PCI_CFG_W32(pcidev, PCIR_CIS, 0);
358
359                                /* Devices have subsytem device and vendor ID */
360                                PCI_CFG_R16(pcidev, PCIR_SUBVEND_0,
361                                                        &dev->subvendor);
362                                PCI_CFG_R16(pcidev, PCIR_SUBDEV_0,
363                                                        &dev->subdevice);
364                        }
365
366                        /* Stop if not a multi-function device */
367                        if (func == 0) {
368                                pci_cfg_r8(pcidev, PCIR_HDRTYPE, &header);
369                                if ((header & PCIM_MFDEV) == 0)
370                                        break;
371                        }
372                }
373        }
374}
375
376static void pci_find_bar(struct pci_dev *dev, int bar)
377{
378        uint32_t size, disable, mask;
379        struct pci_res *res = &dev->resources[bar];
380        pci_dev_t pcidev = dev->busdevfun;
381        int ofs;
382#ifdef DEBUG
383        char *str;
384#define DBG_SET_STR(str, val) str = (val)
385#else
386#define DBG_SET_STR(str, val)
387#endif
388
389        DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
390                PCI_DEV_EXPAND(pcidev), bar);
391
392        res->bar = bar;
393        if (bar == DEV_RES_ROM) {
394                if (dev->flags & PCI_DEV_BRIDGE)
395                        ofs = PCIR_BIOS_1;
396                else
397                        ofs = PCIR_BIOS;
398                disable = 0; /* ROM BARs have a unique enable bit per BAR */
399        } else {
400                ofs = PCIR_BAR(0) + (bar << 2);
401                disable = pci_invalid_address;
402        }
403
404        PCI_CFG_W32(pcidev, ofs, 0xffffffff);
405        PCI_CFG_R32(pcidev, ofs, &size);
406        PCI_CFG_W32(pcidev, ofs, disable);
407
408        if (size == 0 || size == 0xffffffff)
409                return;
410        if (bar == DEV_RES_ROM) {
411                mask = PCIM_BIOS_ADDR_MASK;
412                DBG_SET_STR(str, "ROM");
413                if (dev->bus->flags & PCI_BUS_MEM)
414                        res->flags = PCI_RES_MEM;
415                else
416                        res->flags = PCI_RES_MEMIO;
417        } else if (((size & 0x1) == 0) && (size & 0x6)) {
418                /* unsupported Memory type */
419                PCI_CFG_W32(pcidev, ofs, 0);
420                return;
421        } else {
422                mask = ~0xf;
423                if (size & 0x1) {
424                        /* I/O */
425                        mask = ~0x3;
426                        res->flags = PCI_RES_IO;
427                        DBG_SET_STR(str, "I/O");
428                        if (size & 0xffff0000)
429                                res->flags |= PCI_RES_IO32;
430                        /* Limit size of I/O space to 256 byte */
431                        size |= 0xffffff00;
432                        if ((dev->bus->flags & PCI_BUS_IO) == 0) {
433                                res->flags |= PCI_RES_FAIL;
434                                dev->flags |= PCI_DEV_RES_FAIL;
435                        }
436                } else {
437                        /* Memory. We convert Prefetchable Memory BARs to Memory
438                         * BARs in case the Bridge does not support prefetchable
439                         * memory.
440                         */
441                        if ((size & 0x8) && (dev->bus->flags & PCI_BUS_MEM)) {
442                                /* Prefetchable and Bus supports it */
443                                res->flags = PCI_RES_MEM;
444                                DBG_SET_STR(str, "MEM");
445                        } else {
446                                res->flags = PCI_RES_MEMIO;
447                                DBG_SET_STR(str, "MEMIO");
448                        }
449                }
450        }
451        size &= mask;
452        res->size = ~size + 1;
453        res->boundary = ~size + 1;
454
455        DBG("Bus: %x, Slot: %x, function: %x, %s bar%d size: %x\n",
456                PCI_DEV_EXPAND(pcidev), str, bar, res->size);
457}
458
459static int pci_find_res_dev(struct pci_dev *dev, void *unused)
460{
461        struct pci_bus *bridge;
462        uint32_t tmp;
463        uint16_t tmp16;
464        pci_dev_t pcidev = dev->busdevfun;
465        int i, maxbars;
466
467        if (dev->flags & PCI_DEV_BRIDGE) {
468                /* PCI-PCI Bridge */
469                bridge = (struct pci_bus *)dev;
470
471                /* Only 2 Bridge BARs */
472                maxbars = 2;
473
474                /* Probe Bridge Spaces (MEMIO space always implemented), the
475                 * probe disables all space-decoding at the same time
476                 */
477                PCI_CFG_W32(pcidev, 0x30, 0);
478                PCI_CFG_W16(pcidev, 0x1c, 0x00f0);
479                PCI_CFG_R16(pcidev, 0x1c, &tmp16);
480                if (tmp16 != 0) {
481                        bridge->flags |= PCI_BUS_IO;
482                        if (tmp16 & 0x1)
483                                bridge->flags |= PCI_BUS_IO32;
484                }
485
486                PCI_CFG_W32(pcidev, 0x24, 0x0000ffff);
487                PCI_CFG_R32(pcidev, 0x24, &tmp);
488                if (tmp != 0)
489                        bridge->flags |= PCI_BUS_MEM;
490
491                PCI_CFG_W32(pcidev, 0x20, 0x0000ffff);
492                bridge->flags |= PCI_BUS_MEMIO;
493        } else {
494                /* Normal PCI Device as max 6 BARs */
495                maxbars = 6;
496        }
497
498        /* Probe BARs */
499        for (i = 0; i < maxbars; i++)
500                pci_find_bar(dev, i);
501        pci_find_bar(dev, DEV_RES_ROM);
502
503        return 0;
504}
505
506static int pci_add_res_dev(struct pci_dev *dev, void *arg);
507
508static void pci_add_res_bus(struct pci_bus *bus, int type)
509{
510        int tindex = type - 1;
511
512        /* Clear old resources */
513        bus->busres[tindex] = NULL;
514
515        /* Add resources of devices behind bridge if bridge supports
516         * resource type. If MEM space not supported by bridge, they are
517         * converted to MEMIO in the process.
518         */
519        if (!((type == PCI_BUS_IO) && ((bus->flags & PCI_BUS_IO) == 0))) {
520                pci_for_each_child(bus, pci_add_res_dev, (void *)type, 0);
521
522                /* Reorder Bus resources to fit more optimally (avoid dead
523                 * PCI space). Currently they are sorted by boundary and size.
524                 *
525                 * This is especially important when multiple buses (bridges)
526                 * are present.
527                 */
528                pci_res_reorder(bus->busres[tindex]);
529        }
530}
531
532static int pci_add_res_dev(struct pci_dev *dev, void *arg)
533{
534        int tindex, type = (int)arg;
535        struct pci_bus *bridge;
536        struct pci_res *res, *first_busres;
537        int i;
538        uint32_t bbound;
539
540        /* Type index in Bus resource */
541        tindex = type - 1;
542
543        if (dev->flags & PCI_DEV_BRIDGE) {
544                /* PCI-PCI Bridge. Add all sub-bus resources first */
545                bridge = (struct pci_bus *)dev;
546
547                /* Add all child device's resources to this type */
548                pci_add_res_bus(bridge, type);
549
550                /* Propagate the resources from child bus to BAR on
551                 * this bus, by adding a "fake" BAR per type.
552                 */
553                res = &bridge->dev.resources[BUS_RES_START + tindex];
554                res->bar = BUS_RES_START + tindex;
555                res->start = 0;
556                res->end = 0;
557                res->flags = 0; /* mark BAR resource not available */
558                first_busres = bridge->busres[tindex];
559                if (first_busres) {
560                        res->flags = type;
561                        res->size = pci_res_size(first_busres);
562                        res->boundary = first_busres->boundary;
563                        if (type == PCI_RES_IO) {
564                                bbound = 0x1000; /* Bridge I/O min 4KB */
565                        } else {
566                                bbound = 0x100000; /* Bridge MEM min 1MB */
567
568                                /* Convert MEM to MEMIO if not supported by
569                                 * this bridge
570                                 */
571                                if ((bridge->flags & PCI_BUS_MEM) == 0)
572                                        res->flags = PCI_RES_MEMIO;
573                        }
574                        /* Fulfil minimum bridge boundary */
575                        if (res->boundary < bbound)
576                                res->boundary = bbound;
577                        /* Make sure that size is atleast bridge boundary */
578                        if (res->size > bbound && (res->size & (bbound-1)))
579                                res->size = (res->size | (bbound-1)) + 1;
580                }
581        }
582
583        /* Normal PCI Device as max 6 BARs and a ROM Bar.
584         * Insert BARs into the sorted resource list.
585         */
586        for (i = 0; i < DEV_RES_CNT; i++) {
587                res = &dev->resources[i];
588                if ((res->flags & PCI_RES_TYPE_MASK) != type)
589                        continue;
590                pci_res_insert(&dev->bus->busres[tindex], res);
591        }
592
593        return 0;
594}
595
596/* Function assumes that base is properly aligned to the requirement of the
597 * largest BAR in the system.
598 */
599static uint32_t pci_alloc_res(struct pci_bus *bus, int type,
600                            uint32_t start, uint32_t end)
601{
602        struct pci_dev *dev;
603        struct pci_res *res, **prev_next;
604        unsigned long starttmp;
605        struct pci_bus *bridge;
606        int removed, sec_type;
607
608        /* The resources are sorted on their size (size and alignment is the
609         * same)
610         */
611        prev_next = &bus->busres[type - 1];
612        while ((res = *prev_next) != NULL) {
613
614                dev = RES2DEV(res);
615                removed = 0;
616
617                /* Align start to this reource's need, only needed after
618                 * a bridge resource has been allocated.
619                 */
620                starttmp = (start + (res->boundary-1)) & ~(res->boundary-1);
621
622                if ((starttmp + res->size - 1) > end) {
623                        /* Not enough memory available for this resource */
624                        printk("PCI[%x:%x:%x]: DEV BAR%d (%d): no resource "
625                               "assigned\n",
626                               PCI_DEV_EXPAND(dev->busdevfun),
627                               res->bar, res->flags & PCI_RES_TYPE_MASK);
628                        res->start = res->end = 0;
629
630                        /* If this resources is a bridge window to the
631                         * secondary bus, the secondary resources are not
632                         * changed which has the following effect:
633                         *  I/O    :  Will never be assigned
634                         *  MEMIO  :  Will never be assigned
635                         *  MEM    :  Will stay marked as MEM, but bridge window
636                         *            is changed into MEMIO, when the window is
637                         *            assigned a MEMIO address the secondary
638                         *            resources will also be assigned.
639                         */
640
641                        if (type == PCI_RES_MEM) {
642                                /* Try prefetchable as non-prefetchable mem */
643                                res->flags &= ~PCI_RES_MEM_PREFETCH;
644                                /* Remove resource from MEM list, ideally we
645                                 * should regenerate this list in order to fit
646                                 * the comming BARs more optimially...
647                                 */
648                                *prev_next = res->next;
649                                /* We should not update prev_next here since
650                                 * we just removed the resource from the list
651                                 */
652                                removed = 1;
653                        } else {
654                                res->flags |= PCI_RES_FAIL;
655                                dev->flags |= PCI_DEV_RES_FAIL;
656                        }
657                } else {
658                        start = starttmp;
659
660                        res->start = start;
661                        res->end = start + res->size;
662
663                        /* "Virtual BAR" on a bridge? A bridge resource need all
664                         * its child devices resources allocated
665                         */
666                        if ((res->bar != DEV_RES_ROM) &&
667                            (dev->flags & PCI_DEV_BRIDGE) &&
668                            (res->bar >= BUS_RES_START)) {
669                                bridge = (struct pci_bus *)dev;
670                                /* If MEM bar was changed into a MEMIO the
671                                 * secondary MEM resources are still set to MEM,
672                                 */
673                                if (type == PCI_BUS_MEMIO &&
674                                    res->bar == BRIDGE_RES_MEM)
675                                        sec_type = PCI_RES_MEM;
676                                else
677                                        sec_type = type;
678
679                                pci_alloc_res(bridge, sec_type, res->start,
680                                                res->end);
681                        }
682
683                        start += res->size;
684                }
685                if (removed == 0)
686                        prev_next = &res->next;
687        }
688
689        return start;
690}
691
692static void pci_set_bar(struct pci_dev *dev, int residx)
693{
694        uint32_t tmp;
695        uint16_t tmp16;
696        pci_dev_t pcidev;
697        struct pci_res *res;
698        int is_bridge, ofs;
699
700        res = &dev->resources[residx];
701        pcidev = dev->busdevfun;
702
703        if ((res->flags == 0) || (res->flags & PCI_RES_FAIL))
704                return;
705
706        is_bridge = dev->flags & PCI_DEV_BRIDGE;
707
708        if (res->bar == DEV_RES_ROM) {
709                /* ROM: 32-bit prefetchable memory BAR */
710                if (is_bridge)
711                        ofs = PCIR_BIOS_1;
712                else
713                        ofs = PCIR_BIOS;
714                PCI_CFG_W32(pcidev, ofs, res->start | PCIM_BIOS_ENABLE);
715                DBG("PCI[%x:%x:%x]: ROM BAR: 0x%x-0x%x\n",
716                        PCI_DEV_EXPAND(pcidev), res->start, res->end);
717        } else if (is_bridge && (res->bar == BRIDGE_RES_IO)) {
718                /* PCI Bridge I/O BAR */
719                DBG("PCI[%x:%x:%x]: BAR 1C: 0x%x-0x%x\n",
720                        PCI_DEV_EXPAND(pcidev), res->start, res->end);
721
722                /* Limit and Base */
723                tmp16 = ((res->end-1) & 0x0000f000) |
724                        ((res->start & 0x0000f000) >> 8);
725                tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16);
726
727                DBG("PCI[%x:%x:%x]: BRIDGE BAR 0x%x: 0x%08x [0x30: 0x%x]\n",
728                        PCI_DEV_EXPAND(pcidev), 0x1C, tmp, tmp2);
729                PCI_CFG_W16(pcidev, 0x1C, tmp16);
730                PCI_CFG_W32(pcidev, 0x30, tmp);
731        } else if (is_bridge && (res->bar >= BRIDGE_RES_MEMIO)) {
732                /* PCI Bridge MEM and MEMIO Space */
733
734                /* Limit and Base */
735                tmp = ((res->end-1) & 0xfff00000) | (res->start >> 16);
736
737                DBG("PCI[%x:%x:%x]: BRIDGE BAR 0x%x: 0x%08x\n",
738                        PCI_DEV_EXPAND(pcidev),
739                        0x20 + (res->bar-BRIDGE_RES_MEMIO)*4, tmp);
740                PCI_CFG_W32(pcidev, 0x20+(res->bar-BRIDGE_RES_MEMIO)*4, tmp);
741        } else {
742                /* PCI Device */
743                DBG("PCI[%x:%x:%x]: DEV BAR%d: 0x%08x\n",
744                        PCI_DEV_EXPAND(pcidev), res->bar, res->start);
745                ofs = PCIR_BAR(0) + res->bar*4;
746                PCI_CFG_W32(pcidev, ofs, res->start);
747        }
748
749        /* Enable Memory or I/O responses */
750        if ((res->flags & PCI_RES_TYPE_MASK) == PCI_RES_IO)
751                pci_io_enable(pcidev);
752        else
753                pci_mem_enable(pcidev);
754
755        /* Enable Master if bridge */
756        if (is_bridge)
757                pci_master_enable(pcidev);
758}
759
760static int pci_set_res_dev(struct pci_dev *dev, void *unused)
761{
762        int i, maxbars;
763
764        if (dev->flags & PCI_DEV_BRIDGE)
765                maxbars = 2 + 3; /* 2 BARs + 3 Bridge-Windows "Virtual BARs" */
766        else
767                maxbars = 6; /* Normal PCI Device as max 6 BARs. */
768
769        /* Set BAR resources with previous allocated values */
770        for (i = 0; i < maxbars; i++)
771                pci_set_bar(dev, i);
772        pci_set_bar(dev, DEV_RES_ROM);
773
774        return 0;
775}
776
777/* Route IRQ through PCI-PCI Bridges */
778static int pci_route_irq(pci_dev_t dev, int irq_pin)
779{
780        int slot_grp;
781
782        if (PCI_DEV_BUS(dev) == 0)
783                return irq_pin;
784
785        slot_grp = PCI_DEV_SLOT(dev) & 0x3;
786
787        return (((irq_pin - 1) + slot_grp) & 0x3) + 1;
788}
789
790/* Put assigned system IRQ into PCI interrupt line information field.
791 * This is to make it possible for drivers to read system IRQ / Vector from
792 * configuration space later on.
793 *
794 * 1. Get Interrupt PIN
795 * 2. Route PIN to host bridge
796 * 3. Get System interrupt number assignment for PIN
797 * 4. Set Interrupt LINE
798 */
799static int pci_set_irq_dev(struct pci_dev *dev, void *cfg)
800{
801        struct pci_auto_setup *autocfg = cfg;
802        uint8_t irq_pin, irq_line, *psysirq;
803        pci_dev_t pcidev;
804
805        psysirq = &dev->sysirq;
806        pcidev = dev->busdevfun;
807        PCI_CFG_R8(pcidev, PCIR_INTPIN, &irq_pin);
808
809        /* perform IRQ routing until we reach host bridge */
810        while (dev->bus && irq_pin != 0) {
811                irq_pin = autocfg->irq_route(dev->busdevfun, irq_pin);
812                dev = &dev->bus->dev;
813        }
814
815        /* Get IRQ from PIN on PCI bus0 */
816        if (irq_pin != 0 && autocfg->irq_map)
817                irq_line = autocfg->irq_map(dev->busdevfun, irq_pin);
818        else
819                irq_line = 0;
820
821        *psysirq = irq_line;
822
823        /* Set System Interrupt/Vector for device. 0 means no-IRQ */
824        PCI_CFG_W8(pcidev, PCIR_INTLINE, irq_line);
825
826        return 0;
827}
828
829/* This routine assumes that PCI access library has been successfully
830 * initialized. All information about the PCI bus needed is found in
831 * the pci_auto_cfg structure passed on by pci_config_register().
832 *
833 * The PCI buses are enumerated as bridges are found, PCI devices are
834 * setup with BARs and IRQs, etc.
835 */
836int pci_config_auto(void)
837{
838        uint32_t end;
839        uint32_t startmemio, startmem, startio;
840        struct pci_auto_setup *autocfg = &pci_auto_cfg;
841#ifdef DEBUG
842        uint32_t endmemio, endmem, endio;
843        uint32_t start;
844#endif
845
846        if (pci_config_auto_initialized == 0)
847                return -1; /* no config given to library */
848
849#ifdef DEBUG
850        DBG("\n--- PCI MEMORY AVAILABLE ---\n");
851        if (autocfg->mem_size) {
852                start = autocfg->mem_start;
853                end = autocfg->mem_start + autocfg->mem_size - 1;
854                DBG(" MEM AVAIL [0x%08x-0x%08x]\n", start, end);
855        } else {
856                /* One big memory space */
857                DBG(" MEM share the space with MEMIO\n");
858        }
859        /* no-prefetchable memory space need separate memory space.
860         * For example PCI controller maps this region non-cachable.
861         */
862        start = autocfg->memio_start;
863        end = autocfg->memio_start + autocfg->memio_size - 1;
864        DBG(" MEMIO AVAIL [0x%08x-0x%08x]\n", start, end);
865        if (autocfg->io_size) {
866                start = autocfg->io_start;
867                end = autocfg->io_start + autocfg->io_size - 1;
868                DBG(" I/O AVAIL [0x%08x-0x%08x]\n", start, end);
869        } else {
870                DBG(" I/O Space not available\n");
871        }
872#endif
873
874        /* Init Host-Bridge */
875        memset(&pci_hb, 0, sizeof(pci_hb));
876        pci_hb.dev.flags = PCI_DEV_BRIDGE;
877        if (autocfg->memio_size <= 0)
878                return -1;
879        pci_hb.flags = PCI_BUS_MEMIO;
880        if (autocfg->mem_size)
881                pci_hb.flags |= PCI_BUS_MEM;
882        if (autocfg->io_size)
883                pci_hb.flags |= PCI_BUS_IO;
884
885        /* Find all PCI devices/functions on all buses. The buses will be
886         * enumrated (assigned a unique PCI Bus ID 0..255).
887         */
888        DBG("\n--- PCI SCANNING ---\n");
889        pci_find_devs(&pci_hb);
890        pci_bus_cnt = pci_hb.sord + 1;
891        if (pci_hb.devs == NULL)
892                return 0;
893
894        pci_system_type = PCI_SYSTEM_HOST;
895
896        /* Find all resources (MEM/MEMIO/IO BARs) of all devices/functions
897         * on all buses.
898         *
899         * Device resources behind bridges which does not support prefetchable
900         * memory are already marked as non-prefetchable memory.
901         * Devices which as I/O resources behind a bridge that do not support
902         * I/O space are marked DISABLED.
903         *
904         * All BARs and Bridge Spaces are disabled after this. Only the ones
905         * that are allocated an address are initilized later on.
906         */
907        DBG("\n\n--- PCI RESOURCES ---\n");
908        pci_for_each_dev(pci_find_res_dev, 0);
909
910        /* Add all device's resources to bus and sort them to fit in the PCI
911         * Window. The device resources are propagated upwards through bridges
912         * by adding a "virtual" BAR (boundary != BAR size).
913         *
914         * We wait with MEMIO (non-prefetchable memory) resources to after MEM
915         * resources have been allocated, so that MEM resources can be changed
916         * into MEMIO resources if not enough space.
917         */
918        pci_add_res_bus(&pci_hb, PCI_RES_IO);
919        pci_add_res_bus(&pci_hb, PCI_RES_MEM);
920
921        /* Start assigning found resource according to the sorted order. */
922
923        /* Allocate resources to I/O areas */
924        if (pci_hb.busres[BUS_RES_IO]) {
925                startio = autocfg->io_start;
926                end = startio + autocfg->io_size;
927#ifdef DEBUG
928                endio =
929#endif
930                        pci_alloc_res(&pci_hb, PCI_RES_IO, startio, end);
931        }
932
933        /* Allocate resources to prefetchable memory */
934        if (pci_hb.busres[BUS_RES_MEM]) {
935                startmem = autocfg->mem_start;
936                end = startmem + autocfg->mem_size;
937#ifdef DEBUG
938                endmem =
939#endif
940                        pci_alloc_res(&pci_hb, PCI_RES_MEM, startmem, end);
941        }
942
943        /* Add non-prefetchable memory resources and not fitting prefetchable
944         * memory resources.
945         *
946         * Some prefetchable memory resources may not have fitted into PCI
947         * window. Prefetchable memory can be mapped into non-prefetchable
948         * memory window. The failing BARs have been marked as MEMIO instead.
949         */
950        pci_add_res_bus(&pci_hb, PCI_RES_MEMIO);
951
952        /* Allocate resources to non-prefetchable memory */
953        if (pci_hb.busres[BUS_RES_MEMIO]) {
954                startmemio = autocfg->memio_start;
955                end = startmemio + autocfg->memio_size;
956#ifdef DEBUG
957                endmemio =
958#endif
959                        pci_alloc_res(&pci_hb, PCI_RES_MEMIO, startmemio, end);
960        }
961
962        DBG("\n--- PCI ALLOCATED SPACE RANGES ---\n");
963        DBG(" MEM NON-PREFETCHABLE: [0x%08x-0x%08x]\n", startmemio, endmemio);
964        DBG(" MEM PREFETCHABLE:     [0x%08x-0x%08x]\n", startmem, endmem);
965        DBG(" I/O:                  [0x%08x-0x%08x]\n", startio, endio);
966
967        /* Set all allocated BARs and Bridge Windows */
968        pci_for_each_dev(pci_set_res_dev, NULL);
969
970        /* Initialize IRQs of all devices. According to the PCI-PCI bridge
971         * specification the IRQs are routed differently depending on slot
972         * number. Drivers can override the default routing if a motherboard
973         * requires it.
974         */
975        if ((autocfg->options & CFGOPT_NOSETUP_IRQ) == 0) {
976                if (autocfg->irq_route == NULL) /* use standard irq routing */
977                        autocfg->irq_route = pci_route_irq;
978                pci_for_each_dev(pci_set_irq_dev, autocfg);
979        }
980
981        DBG("PCI resource allocation done\n");
982
983        return 0;
984}
985
986void pci_config_auto_register(void *config)
987{
988        pci_config_auto_initialized = 1;
989        memcpy(&pci_auto_cfg, config, sizeof(struct pci_auto_setup));
990}
Note: See TracBrowser for help on using the repository browser.