source: rtems/cpukit/libpci/pci_cfg_auto.c @ f9fbb333

Last change on this file since f9fbb333 was f9fbb333, checked in by Daniel Hellstrom <daniel@…>, on Aug 30, 2017 at 9:01:38 AM

libpci: fix pci device allocation

The refactoring of pci_dev_create() was incorrect since the code relied on
different defines before including pci/cfg.h. This reverts back to the
original code having two pci_dev_create() one in auto and one in read library.
confdefs.h selectes between the two libraries so both there is no link
conflict.

Updates #3029

  • Property mode set to 100644
File size: 26.6 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.org/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 struct pci_dev *pci_dev_create(int isbus)
271{
272        void *ptr;
273        int size;
274
275        if (isbus)
276                size = sizeof(struct pci_bus);
277        else
278                size = sizeof(struct pci_dev);
279
280        ptr = calloc(1, size);
281        if (!ptr)
282                rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
283        return ptr;
284}
285
286static void pci_find_devs(struct pci_bus *bus)
287{
288        uint32_t id, tmp;
289        uint8_t header;
290        int slot, func, fail;
291        struct pci_dev *dev, **listptr;
292        struct pci_bus *bridge;
293        pci_dev_t pcidev;
294
295        DBG("Scanning bus %d\n", bus->num);
296
297        listptr = &bus->devs;
298        for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
299
300                /* Slot address */
301                pcidev = PCI_DEV(bus->num, slot, 0);
302
303                for (func = 0; func <= PCI_FUNCMAX; func++, pcidev++) {
304
305                        fail = PCI_CFG_R32(pcidev, PCIR_VENDOR, &id);
306                        if (fail || id == 0xffffffff || id == 0) {
307                                /*
308                                 * This slot is empty
309                                 */
310                                if (func == 0)
311                                        break;
312                                else
313                                        continue;
314                        }
315
316                        DBG("Found PCIDEV 0x%x at (bus %x, slot %x, func %x)\n",
317                                                        id, bus, slot, func);
318
319                        /* Set command to reset values, it disables bus
320                         * mastering and address responses.
321                         */
322                        PCI_CFG_W16(pcidev, PCIR_COMMAND, 0);
323
324                        /* Clear any already set status bits */
325                        PCI_CFG_W16(pcidev, PCIR_STATUS, 0xf900);
326
327                        /* Set latency timer to 64 */
328                        PCI_CFG_W8(pcidev, PCIR_LATTIMER, 64);
329
330                        PCI_CFG_R32(pcidev, PCIR_REVID, &tmp);
331                        tmp >>= 16;
332                        dev = pci_dev_create(tmp == PCID_PCI2PCI_BRIDGE);
333                        *listptr = dev;
334                        listptr = &dev->next;
335
336                        dev->busdevfun = pcidev;
337                        dev->bus = bus;
338                        PCI_CFG_R16(pcidev, PCIR_VENDOR, &dev->vendor);
339                        PCI_CFG_R16(pcidev, PCIR_DEVICE, &dev->device);
340                        PCI_CFG_R32(pcidev, PCIR_REVID, &dev->classrev);
341
342                        if (tmp == PCID_PCI2PCI_BRIDGE) {
343                                DBG("Found PCI-PCI Bridge 0x%x at "
344                                    "(bus %x, slot %x, func %x)\n",
345                                    id, bus, slot, func);
346                                dev->flags = PCI_DEV_BRIDGE;
347                                dev->subvendor = 0;
348                                dev->subdevice = 0;
349                                bridge = (struct pci_bus *)dev;
350                                bridge->num = bus->sord + 1;
351                                bridge->pri = bus->num;
352                                bridge->sord = bus->sord + 1;
353
354                                /* Configure bridge (no support for 64-bit) */
355                                PCI_CFG_W32(pcidev, 0x28, 0);
356                                PCI_CFG_W32(pcidev, 0x2C, 0);
357                                tmp = (64 << 24) | (0xff << 16) |
358                                      (bridge->num << 8) | bridge->pri;
359                                PCI_CFG_W32(pcidev, PCIR_PRIBUS_1, tmp);
360
361                                /* Scan Secondary Bus */
362                                pci_find_devs(bridge);
363
364                                /* sord might have been updated */
365                                PCI_CFG_W8(pcidev, 0x1a, bridge->sord);
366                                bus->sord = bridge->sord;
367
368                                DBG("PCI-PCI BRIDGE: Primary %x, Secondary %x, "
369                                    "Subordinate %x\n",
370                                    bridge->pri, bridge->num, bridge->sord);
371                        } else {
372                                /* Disable Cardbus CIS Pointer */
373                                PCI_CFG_W32(pcidev, PCIR_CIS, 0);
374
375                                /* Devices have subsytem device and vendor ID */
376                                PCI_CFG_R16(pcidev, PCIR_SUBVEND_0,
377                                                        &dev->subvendor);
378                                PCI_CFG_R16(pcidev, PCIR_SUBDEV_0,
379                                                        &dev->subdevice);
380                        }
381
382                        /* Stop if not a multi-function device */
383                        if (func == 0) {
384                                pci_cfg_r8(pcidev, PCIR_HDRTYPE, &header);
385                                if ((header & PCIM_MFDEV) == 0)
386                                        break;
387                        }
388                }
389        }
390}
391
392static void pci_find_bar(struct pci_dev *dev, int bar)
393{
394        uint32_t size, disable, mask;
395        struct pci_res *res = &dev->resources[bar];
396        pci_dev_t pcidev = dev->busdevfun;
397        int ofs;
398#ifdef DEBUG
399        char *str;
400#define DBG_SET_STR(str, val) str = (val)
401#else
402#define DBG_SET_STR(str, val)
403#endif
404
405        DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
406                PCI_DEV_EXPAND(pcidev), bar);
407
408        res->bar = bar;
409        if (bar == DEV_RES_ROM) {
410                if (dev->flags & PCI_DEV_BRIDGE)
411                        ofs = PCIR_BIOS_1;
412                else
413                        ofs = PCIR_BIOS;
414                disable = 0; /* ROM BARs have a unique enable bit per BAR */
415        } else {
416                ofs = PCIR_BAR(0) + (bar << 2);
417                disable = pci_invalid_address;
418        }
419
420        PCI_CFG_W32(pcidev, ofs, 0xffffffff);
421        PCI_CFG_R32(pcidev, ofs, &size);
422        PCI_CFG_W32(pcidev, ofs, disable);
423
424        if (size == 0 || size == 0xffffffff)
425                return;
426        if (bar == DEV_RES_ROM) {
427                mask = PCIM_BIOS_ADDR_MASK;
428                DBG_SET_STR(str, "ROM");
429                if (dev->bus->flags & PCI_BUS_MEM)
430                        res->flags = PCI_RES_MEM;
431                else
432                        res->flags = PCI_RES_MEMIO;
433        } else if (((size & 0x1) == 0) && (size & 0x6)) {
434                /* unsupported Memory type */
435                PCI_CFG_W32(pcidev, ofs, 0);
436                return;
437        } else {
438                mask = ~0xf;
439                if (size & 0x1) {
440                        /* I/O */
441                        mask = ~0x3;
442                        res->flags = PCI_RES_IO;
443                        DBG_SET_STR(str, "I/O");
444                        if (size & 0xffff0000)
445                                res->flags |= PCI_RES_IO32;
446                        /* Limit size of I/O space to 256 byte */
447                        size |= 0xffffff00;
448                        if ((dev->bus->flags & PCI_BUS_IO) == 0) {
449                                res->flags |= PCI_RES_FAIL;
450                                dev->flags |= PCI_DEV_RES_FAIL;
451                        }
452                } else {
453                        /* Memory. We convert Prefetchable Memory BARs to Memory
454                         * BARs in case the Bridge does not support prefetchable
455                         * memory.
456                         */
457                        if ((size & 0x8) && (dev->bus->flags & PCI_BUS_MEM)) {
458                                /* Prefetchable and Bus supports it */
459                                res->flags = PCI_RES_MEM;
460                                DBG_SET_STR(str, "MEM");
461                        } else {
462                                res->flags = PCI_RES_MEMIO;
463                                DBG_SET_STR(str, "MEMIO");
464                        }
465                }
466        }
467        size &= mask;
468        res->size = ~size + 1;
469        res->boundary = ~size + 1;
470
471        DBG("Bus: %x, Slot: %x, function: %x, %s bar%d size: %x\n",
472                PCI_DEV_EXPAND(pcidev), str, bar, res->size);
473}
474
475static int pci_find_res_dev(struct pci_dev *dev, void *unused)
476{
477        struct pci_bus *bridge;
478        uint32_t tmp;
479        uint16_t tmp16;
480        pci_dev_t pcidev = dev->busdevfun;
481        int i, maxbars;
482
483        if (dev->flags & PCI_DEV_BRIDGE) {
484                /* PCI-PCI Bridge */
485                bridge = (struct pci_bus *)dev;
486
487                /* Only 2 Bridge BARs */
488                maxbars = 2;
489
490                /* Probe Bridge Spaces (MEMIO space always implemented), the
491                 * probe disables all space-decoding at the same time
492                 */
493                PCI_CFG_W32(pcidev, 0x30, 0);
494                PCI_CFG_W16(pcidev, 0x1c, 0x00f0);
495                PCI_CFG_R16(pcidev, 0x1c, &tmp16);
496                if (tmp16 != 0) {
497                        bridge->flags |= PCI_BUS_IO;
498                        if (tmp16 & 0x1)
499                                bridge->flags |= PCI_BUS_IO32;
500                }
501
502                PCI_CFG_W32(pcidev, 0x24, 0x0000ffff);
503                PCI_CFG_R32(pcidev, 0x24, &tmp);
504                if (tmp != 0)
505                        bridge->flags |= PCI_BUS_MEM;
506
507                PCI_CFG_W32(pcidev, 0x20, 0x0000ffff);
508                bridge->flags |= PCI_BUS_MEMIO;
509        } else {
510                /* Normal PCI Device as max 6 BARs */
511                maxbars = 6;
512        }
513
514        /* Probe BARs */
515        for (i = 0; i < maxbars; i++)
516                pci_find_bar(dev, i);
517        pci_find_bar(dev, DEV_RES_ROM);
518
519        return 0;
520}
521
522static int pci_add_res_dev(struct pci_dev *dev, void *arg);
523
524static void pci_add_res_bus(struct pci_bus *bus, int type)
525{
526        int tindex = type - 1;
527
528        /* Clear old resources */
529        bus->busres[tindex] = NULL;
530
531        /* Add resources of devices behind bridge if bridge supports
532         * resource type. If MEM space not supported by bridge, they are
533         * converted to MEMIO in the process.
534         */
535        if (!((type == PCI_BUS_IO) && ((bus->flags & PCI_BUS_IO) == 0))) {
536                pci_for_each_child(bus, pci_add_res_dev, (void *)type, 0);
537
538                /* Reorder Bus resources to fit more optimally (avoid dead
539                 * PCI space). Currently they are sorted by boundary and size.
540                 *
541                 * This is especially important when multiple buses (bridges)
542                 * are present.
543                 */
544                pci_res_reorder(bus->busres[tindex]);
545        }
546}
547
548static int pci_add_res_dev(struct pci_dev *dev, void *arg)
549{
550        int tindex, type = (int)arg;
551        struct pci_bus *bridge;
552        struct pci_res *res, *first_busres;
553        int i;
554        uint32_t bbound;
555
556        /* Type index in Bus resource */
557        tindex = type - 1;
558
559        if (dev->flags & PCI_DEV_BRIDGE) {
560                /* PCI-PCI Bridge. Add all sub-bus resources first */
561                bridge = (struct pci_bus *)dev;
562
563                /* Add all child device's resources to this type */
564                pci_add_res_bus(bridge, type);
565
566                /* Propagate the resources from child bus to BAR on
567                 * this bus, by adding a "fake" BAR per type.
568                 */
569                res = &bridge->dev.resources[BUS_RES_START + tindex];
570                res->bar = BUS_RES_START + tindex;
571                res->start = 0;
572                res->end = 0;
573                res->flags = 0; /* mark BAR resource not available */
574                first_busres = bridge->busres[tindex];
575                if (first_busres) {
576                        res->flags = type;
577                        res->size = pci_res_size(first_busres);
578                        res->boundary = first_busres->boundary;
579                        if (type == PCI_RES_IO) {
580                                bbound = 0x1000; /* Bridge I/O min 4KB */
581                        } else {
582                                bbound = 0x100000; /* Bridge MEM min 1MB */
583
584                                /* Convert MEM to MEMIO if not supported by
585                                 * this bridge
586                                 */
587                                if ((bridge->flags & PCI_BUS_MEM) == 0)
588                                        res->flags = PCI_RES_MEMIO;
589                        }
590                        /* Fulfil minimum bridge boundary */
591                        if (res->boundary < bbound)
592                                res->boundary = bbound;
593                        /* Make sure that size is atleast bridge boundary */
594                        if (res->size > bbound && (res->size & (bbound-1)))
595                                res->size = (res->size | (bbound-1)) + 1;
596                }
597        }
598
599        /* Normal PCI Device as max 6 BARs and a ROM Bar.
600         * Insert BARs into the sorted resource list.
601         */
602        for (i = 0; i < DEV_RES_CNT; i++) {
603                res = &dev->resources[i];
604                if ((res->flags & PCI_RES_TYPE_MASK) != type)
605                        continue;
606                pci_res_insert(&dev->bus->busres[tindex], res);
607        }
608
609        return 0;
610}
611
612/* Function assumes that base is properly aligned to the requirement of the
613 * largest BAR in the system.
614 */
615static uint32_t pci_alloc_res(struct pci_bus *bus, int type,
616                            uint32_t start, uint32_t end)
617{
618        struct pci_dev *dev;
619        struct pci_res *res, **prev_next;
620        unsigned long starttmp;
621        struct pci_bus *bridge;
622        int removed, sec_type;
623
624        /* The resources are sorted on their size (size and alignment is the
625         * same)
626         */
627        prev_next = &bus->busres[type - 1];
628        while ((res = *prev_next) != NULL) {
629
630                dev = RES2DEV(res);
631                removed = 0;
632
633                /* Align start to this reource's need, only needed after
634                 * a bridge resource has been allocated.
635                 */
636                starttmp = (start + (res->boundary-1)) & ~(res->boundary-1);
637
638                if ((starttmp + res->size - 1) > end) {
639                        /* Not enough memory available for this resource */
640                        printk("PCI[%x:%x:%x]: DEV BAR%d (%d): no resource "
641                               "assigned\n",
642                               PCI_DEV_EXPAND(dev->busdevfun),
643                               res->bar, res->flags & PCI_RES_TYPE_MASK);
644                        res->start = res->end = 0;
645
646                        /* If this resources is a bridge window to the
647                         * secondary bus, the secondary resources are not
648                         * changed which has the following effect:
649                         *  I/O    :  Will never be assigned
650                         *  MEMIO  :  Will never be assigned
651                         *  MEM    :  Will stay marked as MEM, but bridge window
652                         *            is changed into MEMIO, when the window is
653                         *            assigned a MEMIO address the secondary
654                         *            resources will also be assigned.
655                         */
656
657                        if (type == PCI_RES_MEM) {
658                                /* Try prefetchable as non-prefetchable mem */
659                                res->flags &= ~PCI_RES_MEM_PREFETCH;
660                                /* Remove resource from MEM list, ideally we
661                                 * should regenerate this list in order to fit
662                                 * the comming BARs more optimially...
663                                 */
664                                *prev_next = res->next;
665                                /* We should not update prev_next here since
666                                 * we just removed the resource from the list
667                                 */
668                                removed = 1;
669                        } else {
670                                res->flags |= PCI_RES_FAIL;
671                                dev->flags |= PCI_DEV_RES_FAIL;
672                        }
673                } else {
674                        start = starttmp;
675
676                        res->start = start;
677                        res->end = start + res->size;
678
679                        /* "Virtual BAR" on a bridge? A bridge resource need all
680                         * its child devices resources allocated
681                         */
682                        if ((res->bar != DEV_RES_ROM) &&
683                            (dev->flags & PCI_DEV_BRIDGE) &&
684                            (res->bar >= BUS_RES_START)) {
685                                bridge = (struct pci_bus *)dev;
686                                /* If MEM bar was changed into a MEMIO the
687                                 * secondary MEM resources are still set to MEM,
688                                 */
689                                if (type == PCI_BUS_MEMIO &&
690                                    res->bar == BRIDGE_RES_MEM)
691                                        sec_type = PCI_RES_MEM;
692                                else
693                                        sec_type = type;
694
695                                pci_alloc_res(bridge, sec_type, res->start,
696                                                res->end);
697                        }
698
699                        start += res->size;
700                }
701                if (removed == 0)
702                        prev_next = &res->next;
703        }
704
705        return start;
706}
707
708static void pci_set_bar(struct pci_dev *dev, int residx)
709{
710        uint32_t tmp;
711        uint16_t tmp16;
712        pci_dev_t pcidev;
713        struct pci_res *res;
714        int is_bridge, ofs;
715
716        res = &dev->resources[residx];
717        pcidev = dev->busdevfun;
718
719        if ((res->flags == 0) || (res->flags & PCI_RES_FAIL))
720                return;
721
722        is_bridge = dev->flags & PCI_DEV_BRIDGE;
723
724        if (res->bar == DEV_RES_ROM) {
725                /* ROM: 32-bit prefetchable memory BAR */
726                if (is_bridge)
727                        ofs = PCIR_BIOS_1;
728                else
729                        ofs = PCIR_BIOS;
730                PCI_CFG_W32(pcidev, ofs, res->start | PCIM_BIOS_ENABLE);
731                DBG("PCI[%x:%x:%x]: ROM BAR: 0x%x-0x%x\n",
732                        PCI_DEV_EXPAND(pcidev), res->start, res->end);
733        } else if (is_bridge && (res->bar == BRIDGE_RES_IO)) {
734                /* PCI Bridge I/O BAR */
735                DBG("PCI[%x:%x:%x]: BAR 1C: 0x%x-0x%x\n",
736                        PCI_DEV_EXPAND(pcidev), res->start, res->end);
737
738                /* Limit and Base */
739                tmp16 = ((res->end-1) & 0x0000f000) |
740                        ((res->start & 0x0000f000) >> 8);
741                tmp = ((res->end-1) & 0xffff0000) | (res->start >> 16);
742
743                DBG("PCI[%x:%x:%x]: BRIDGE BAR 0x%x: 0x%08x [0x30: 0x%x]\n",
744                        PCI_DEV_EXPAND(pcidev), 0x1C, tmp, tmp2);
745                PCI_CFG_W16(pcidev, 0x1C, tmp16);
746                PCI_CFG_W32(pcidev, 0x30, tmp);
747        } else if (is_bridge && (res->bar >= BRIDGE_RES_MEMIO)) {
748                /* PCI Bridge MEM and MEMIO Space */
749
750                /* Limit and Base */
751                tmp = ((res->end-1) & 0xfff00000) | (res->start >> 16);
752
753                DBG("PCI[%x:%x:%x]: BRIDGE BAR 0x%x: 0x%08x\n",
754                        PCI_DEV_EXPAND(pcidev),
755                        0x20 + (res->bar-BRIDGE_RES_MEMIO)*4, tmp);
756                PCI_CFG_W32(pcidev, 0x20+(res->bar-BRIDGE_RES_MEMIO)*4, tmp);
757        } else {
758                /* PCI Device */
759                DBG("PCI[%x:%x:%x]: DEV BAR%d: 0x%08x\n",
760                        PCI_DEV_EXPAND(pcidev), res->bar, res->start);
761                ofs = PCIR_BAR(0) + res->bar*4;
762                PCI_CFG_W32(pcidev, ofs, res->start);
763        }
764
765        /* Enable Memory or I/O responses */
766        if ((res->flags & PCI_RES_TYPE_MASK) == PCI_RES_IO)
767                pci_io_enable(pcidev);
768        else
769                pci_mem_enable(pcidev);
770
771        /* Enable Master if bridge */
772        if (is_bridge)
773                pci_master_enable(pcidev);
774}
775
776static int pci_set_res_dev(struct pci_dev *dev, void *unused)
777{
778        int i, maxbars;
779
780        if (dev->flags & PCI_DEV_BRIDGE)
781                maxbars = 2 + 3; /* 2 BARs + 3 Bridge-Windows "Virtual BARs" */
782        else
783                maxbars = 6; /* Normal PCI Device as max 6 BARs. */
784
785        /* Set BAR resources with previous allocated values */
786        for (i = 0; i < maxbars; i++)
787                pci_set_bar(dev, i);
788        pci_set_bar(dev, DEV_RES_ROM);
789
790        return 0;
791}
792
793/* Route IRQ through PCI-PCI Bridges */
794static int pci_route_irq(pci_dev_t dev, int irq_pin)
795{
796        int slot_grp;
797
798        if (PCI_DEV_BUS(dev) == 0)
799                return irq_pin;
800
801        slot_grp = PCI_DEV_SLOT(dev) & 0x3;
802
803        return (((irq_pin - 1) + slot_grp) & 0x3) + 1;
804}
805
806/* Put assigned system IRQ into PCI interrupt line information field.
807 * This is to make it possible for drivers to read system IRQ / Vector from
808 * configuration space later on.
809 *
810 * 1. Get Interrupt PIN
811 * 2. Route PIN to host bridge
812 * 3. Get System interrupt number assignment for PIN
813 * 4. Set Interrupt LINE
814 */
815static int pci_set_irq_dev(struct pci_dev *dev, void *cfg)
816{
817        struct pci_auto_setup *autocfg = cfg;
818        uint8_t irq_pin, irq_line, *psysirq;
819        pci_dev_t pcidev;
820
821        psysirq = &dev->sysirq;
822        pcidev = dev->busdevfun;
823        PCI_CFG_R8(pcidev, PCIR_INTPIN, &irq_pin);
824
825        /* perform IRQ routing until we reach host bridge */
826        while (dev->bus && irq_pin != 0) {
827                irq_pin = autocfg->irq_route(dev->busdevfun, irq_pin);
828                dev = &dev->bus->dev;
829        }
830
831        /* Get IRQ from PIN on PCI bus0 */
832        if (irq_pin != 0 && autocfg->irq_map)
833                irq_line = autocfg->irq_map(dev->busdevfun, irq_pin);
834        else
835                irq_line = 0;
836
837        *psysirq = irq_line;
838
839        /* Set System Interrupt/Vector for device. 0 means no-IRQ */
840        PCI_CFG_W8(pcidev, PCIR_INTLINE, irq_line);
841
842        return 0;
843}
844
845/* This routine assumes that PCI access library has been successfully
846 * initialized. All information about the PCI bus needed is found in
847 * the pci_auto_cfg structure passed on by pci_config_register().
848 *
849 * The PCI buses are enumerated as bridges are found, PCI devices are
850 * setup with BARs and IRQs, etc.
851 */
852int pci_config_auto(void)
853{
854        uint32_t end;
855        uint32_t startmemio, startmem, startio;
856        struct pci_auto_setup *autocfg = &pci_auto_cfg;
857#ifdef DEBUG
858        uint32_t endmemio, endmem, endio;
859        uint32_t start;
860#endif
861
862        if (pci_config_auto_initialized == 0)
863                return -1; /* no config given to library */
864
865#ifdef DEBUG
866        DBG("\n--- PCI MEMORY AVAILABLE ---\n");
867        if (autocfg->mem_size) {
868                start = autocfg->mem_start;
869                end = autocfg->mem_start + autocfg->mem_size - 1;
870                DBG(" MEM AVAIL [0x%08x-0x%08x]\n", start, end);
871        } else {
872                /* One big memory space */
873                DBG(" MEM share the space with MEMIO\n");
874        }
875        /* no-prefetchable memory space need separate memory space.
876         * For example PCI controller maps this region non-cachable.
877         */
878        start = autocfg->memio_start;
879        end = autocfg->memio_start + autocfg->memio_size - 1;
880        DBG(" MEMIO AVAIL [0x%08x-0x%08x]\n", start, end);
881        if (autocfg->io_size) {
882                start = autocfg->io_start;
883                end = autocfg->io_start + autocfg->io_size - 1;
884                DBG(" I/O AVAIL [0x%08x-0x%08x]\n", start, end);
885        } else {
886                DBG(" I/O Space not available\n");
887        }
888#endif
889
890        /* Init Host-Bridge */
891        memset(&pci_hb, 0, sizeof(pci_hb));
892        pci_hb.dev.flags = PCI_DEV_BRIDGE;
893        if (autocfg->memio_size <= 0)
894                return -1;
895        pci_hb.flags = PCI_BUS_MEMIO;
896        if (autocfg->mem_size)
897                pci_hb.flags |= PCI_BUS_MEM;
898        if (autocfg->io_size)
899                pci_hb.flags |= PCI_BUS_IO;
900
901        /* Find all PCI devices/functions on all buses. The buses will be
902         * enumrated (assigned a unique PCI Bus ID 0..255).
903         */
904        DBG("\n--- PCI SCANNING ---\n");
905        pci_find_devs(&pci_hb);
906        pci_bus_cnt = pci_hb.sord + 1;
907        if (pci_hb.devs == NULL)
908                return 0;
909
910        pci_system_type = PCI_SYSTEM_HOST;
911
912        /* Find all resources (MEM/MEMIO/IO BARs) of all devices/functions
913         * on all buses.
914         *
915         * Device resources behind bridges which does not support prefetchable
916         * memory are already marked as non-prefetchable memory.
917         * Devices which as I/O resources behind a bridge that do not support
918         * I/O space are marked DISABLED.
919         *
920         * All BARs and Bridge Spaces are disabled after this. Only the ones
921         * that are allocated an address are initilized later on.
922         */
923        DBG("\n\n--- PCI RESOURCES ---\n");
924        pci_for_each_dev(pci_find_res_dev, 0);
925
926        /* Add all device's resources to bus and sort them to fit in the PCI
927         * Window. The device resources are propagated upwards through bridges
928         * by adding a "virtual" BAR (boundary != BAR size).
929         *
930         * We wait with MEMIO (non-prefetchable memory) resources to after MEM
931         * resources have been allocated, so that MEM resources can be changed
932         * into MEMIO resources if not enough space.
933         */
934        pci_add_res_bus(&pci_hb, PCI_RES_IO);
935        pci_add_res_bus(&pci_hb, PCI_RES_MEM);
936
937        /* Start assigning found resource according to the sorted order. */
938
939        /* Allocate resources to I/O areas */
940        if (pci_hb.busres[BUS_RES_IO]) {
941                startio = autocfg->io_start;
942                end = startio + autocfg->io_size;
943#ifdef DEBUG
944                endio =
945#endif
946                        pci_alloc_res(&pci_hb, PCI_RES_IO, startio, end);
947        }
948
949        /* Allocate resources to prefetchable memory */
950        if (pci_hb.busres[BUS_RES_MEM]) {
951                startmem = autocfg->mem_start;
952                end = startmem + autocfg->mem_size;
953#ifdef DEBUG
954                endmem =
955#endif
956                        pci_alloc_res(&pci_hb, PCI_RES_MEM, startmem, end);
957        }
958
959        /* Add non-prefetchable memory resources and not fitting prefetchable
960         * memory resources.
961         *
962         * Some prefetchable memory resources may not have fitted into PCI
963         * window. Prefetchable memory can be mapped into non-prefetchable
964         * memory window. The failing BARs have been marked as MEMIO instead.
965         */
966        pci_add_res_bus(&pci_hb, PCI_RES_MEMIO);
967
968        /* Allocate resources to non-prefetchable memory */
969        if (pci_hb.busres[BUS_RES_MEMIO]) {
970                startmemio = autocfg->memio_start;
971                end = startmemio + autocfg->memio_size;
972#ifdef DEBUG
973                endmemio =
974#endif
975                        pci_alloc_res(&pci_hb, PCI_RES_MEMIO, startmemio, end);
976        }
977
978        DBG("\n--- PCI ALLOCATED SPACE RANGES ---\n");
979        DBG(" MEM NON-PREFETCHABLE: [0x%08x-0x%08x]\n", startmemio, endmemio);
980        DBG(" MEM PREFETCHABLE:     [0x%08x-0x%08x]\n", startmem, endmem);
981        DBG(" I/O:                  [0x%08x-0x%08x]\n", startio, endio);
982
983        /* Set all allocated BARs and Bridge Windows */
984        pci_for_each_dev(pci_set_res_dev, NULL);
985
986        /* Initialize IRQs of all devices. According to the PCI-PCI bridge
987         * specification the IRQs are routed differently depending on slot
988         * number. Drivers can override the default routing if a motherboard
989         * requires it.
990         */
991        if ((autocfg->options & CFGOPT_NOSETUP_IRQ) == 0) {
992                if (autocfg->irq_route == NULL) /* use standard irq routing */
993                        autocfg->irq_route = pci_route_irq;
994                pci_for_each_dev(pci_set_irq_dev, autocfg);
995        }
996
997        DBG("PCI resource allocation done\n");
998
999        return 0;
1000}
1001
1002void pci_config_auto_register(void *config)
1003{
1004        pci_config_auto_initialized = 1;
1005        memcpy(&pci_auto_cfg, config, sizeof(struct pci_auto_setup));
1006}
Note: See TracBrowser for help on using the repository browser.