Fwd: [PATCH 007/111] LIBPCI: added PCI layer to cpukit/libpci

Gedare Bloom gedare at rtems.org
Fri Feb 27 17:28:53 UTC 2015


Followup from your reply:
* Using FreeBSD defines/code would be acceptable.
* Using the uintptr_t* construction may or may not work in RES2DEV
because pointer arithmetic on uintptr_t* may yield uncertain results
due to integer rather than byte math. (Although subtracting the two
pointer types as you do it should work.) You can also cast a pointer
to a uintptr_t directly, so I might use:
#define RES2DEV(res) ((struct pci_dev *) \
    ((uintptr_t)res - (uintptr_t)(res->bar * (sizeof(struct pci_res)))))

[...]
Continuing on from "This is all the farther I got for now."

My comments regarding doxygen can be delayed, but should be added to
the TODOs for this code-base. Although it would be nice for this code
to follow the RTEMS Coding Conventions, it may not be necessary since
this is really a self-contained third-party library. If there is a
style guide you do use, it may be nice to indicate it somewhere (for
both pci and drvmgr).

> diff --git a/cpukit/libpci/pci/irq.h b/cpukit/libpci/pci/irq.h
> new file mode 100644
> index 0000000..2dacadf
> --- /dev/null
> +++ b/cpukit/libpci/pci/irq.h
> @@ -0,0 +1,105 @@
> +/* PCI IRQ Library
> + *
> + * IRQ handling does not have so much with PCI to do, this library depends
> + * on the BSP to implement shared interrupts.
> + *
We've gone away from embedding file description comments in the
copyright/license block, and instead put a brief doxygen block at the
start of the file, followed by the copyright/license. See:
https://devel.rtems.org/wiki/Developer/Coding/Boilerplate_File_Header

> + * COPYRIGHT (c) 2010.
> + * Cobham Gaisler AB.
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.com/license/LICENSE.
> + */
> +
> +#ifndef __PCI_IRQ_H__
> +#define __PCI_IRQ_H__
> +
> +#include <bsp.h>
> +
> +/* PCI Handler (ISR) called when IRQ is generated by any of the PCI devices
> + * connected to the same PCI IRQ Pin. This is been defined the same way as
s/is/has

> + * rtems_interrupt_handler in order for BSPs to "direct-map" the register
> + * and unregister functions rtems_interrupt_handler_install/remove
> + */
> +typedef void (*pci_isr)(void *arg);
> +
Why not use rtems_interrupt_handler directly?

> +/* Get assigned system IRQ to a PCI Device. If no IRQ 0 is returned */
> +extern int pci_dev_irq(pci_dev_t dev);
> +
> +/* Register shared PCI IRQ handler, but does not enable it. The system interrupt
> + * number is read from the PCI board's PCI configuration space header iline
> + * field. The iline field is initialized by the PCI subsystem during start up,
> + * the ipin field is translated into a system IRQ and written to iline. The
> + * board's driver should use the iline field as the irq argument to this
> + * function.
> + *
> + * Arguments
> + *  irq       System IRQ number, normally taken from the PCI configuration area
> + *  isr       Function pointer to the ISR
> + *  arg       Second argument to function isr
> + */
> +static inline int pci_interrupt_register(int irq, const char *info,
Use RTEMS_INLINE_ROUTINE instead of "static inline".
https://lists.rtems.org/pipermail/users/2011-November/024226.html

[...]

> diff --git a/cpukit/libpci/pci_access_mem_be.c b/cpukit/libpci/pci_access_mem_be.c
> new file mode 100644
> index 0000000..f05b547
> --- /dev/null
> +++ b/cpukit/libpci/pci_access_mem_be.c
> @@ -0,0 +1,67 @@
> +/*  PCI Access Library
> + *  Registers-over-Memory Space - Generic Big endian PCI bus definitions
> + *
> + *  COPYRIGHT (c) 2010.
> + *  Cobham Gaisler AB.
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.com/license/LICENSE.
> + */
> +
> +#include <pci.h>
> +
> +uint16_t pci_mem_be_ld_le16(uint16_t *adr)
> +{
> +       return ld_be16(adr);
> +}
> +
> +uint16_t pci_mem_be_ld_be16(uint16_t *adr)
> +{
> +       return ld_le16(adr);
> +}
> +
> +uint32_t pci_mem_be_ld_le32(uint32_t *adr)
> +{
> +       return ld_be32(adr);
> +}
> +
> +uint32_t pci_mem_be_ld_be32(uint32_t *adr)
> +{
> +       return ld_le32(adr);
> +}
> +
> +void pci_mem_be_st_le16(uint16_t *adr, uint16_t data)
> +{
> +       st_be16(adr, data);
> +}
> +
> +void pci_mem_be_st_be16(uint16_t *adr, uint16_t data)
> +{
> +       st_le16(adr, data);
> +}
> +
> +void pci_mem_be_st_le32(uint32_t *adr, uint32_t data)
> +{
> +       st_be32(adr, data);
> +}
> +
> +void pci_mem_be_st_be32(uint32_t *adr, uint32_t data)
> +{
> +       st_le32(adr, data);
> +}
> +
> +struct pci_memreg_ops pci_mem_be_ops = {
> +       .ld8    = pci_mem_ld8,
> +       .st8    = pci_mem_st8,
> +
> +       .ld_le16 = pci_mem_be_ld_le16,
> +       .st_le16 = pci_mem_be_st_le16,
> +       .ld_be16 = pci_mem_be_ld_be16,
> +       .st_be16 = pci_mem_be_st_be16,
> +
> +       .ld_le32 = pci_mem_be_ld_le32,
> +       .st_le32 = pci_mem_be_st_le32,
> +       .ld_be32 = pci_mem_be_ld_be32,
> +       .st_be32 = pci_mem_be_st_be32,
> +};
functions used only through function pointers should be declared
static inline (RTEMS_INLINE_ROUTINE).

> diff --git a/cpukit/libpci/pci_cfg.c b/cpukit/libpci/pci_cfg.c
> new file mode 100644
> index 0000000..78a1229
> --- /dev/null
> +++ b/cpukit/libpci/pci_cfg.c
> @@ -0,0 +1,55 @@
> +/*  PCI Configuration Library
> + *
> + *  COPYRIGHT (c) 2010.
> + *  Cobham Gaisler AB.
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.com/license/LICENSE.
> + */
> +
> +#include <pci/cfg.h>
> +
> +/* Number of buses. This is set from respective library */
> +int pci_bus_cnt = 0;
> +
> +/* PCI Address assigned to BARs which failed to fit into the PCI Window or
> + * is disabled by any other cause.
> + */
> +uint32_t pci_invalid_address = 0;
Should this be a pointer or maybe a uintptr_t?

> +
> +/* PCI System type. Configuration Library setup this */
> +int pci_system_type = PCI_SYSTEM_NONE;
> +
If the enum type were declared, this would get type-checked.

[...]

> diff --git a/cpukit/libpci/pci_cfg_auto.c b/cpukit/libpci/pci_cfg_auto.c
> new file mode 100644
> index 0000000..548dd90
> --- /dev/null
> +++ b/cpukit/libpci/pci_cfg_auto.c
> @@ -0,0 +1,1014 @@
> +/*  PCI (Auto) configuration Library. Setup PCI configuration space and IRQ.
> + *
> + *  COPYRIGHT (c) 2010.
> + *  Cobham Gaisler AB.
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.com/license/LICENSE.
> + */
> +
> +#include <rtems.h>
> +#include <stdlib.h>
> +#include <rtems/bspIo.h>
> +#include <string.h>
> +
> +/* Configure headers */
> +#define PCI_CFG_AUTO_LIB
> +
> +#include <pci.h>
> +#include <pci/access.h>
> +#include <pci/cfg.h>
> +
> +/* Define PCI_INFO_ON_STARTUP to get a listing of configured devices at boot
> + * time
> + */
> +#undef PCI_INFO_ON_STARTUP
I'm not sure what this is for.

> +
> +/* #define DEBUG */
Could replace this with RTEMS_DEBUG.

> +
> +#ifdef DEBUG
> +#define DBG(x...) printk(x)
> +#else
> +#define DBG(x...)
> +#endif
> +
> +/* PCI Library
> + * (For debugging it might be good to use other functions or the driver's
> + *  directly)
> + */
> +#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
> +#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
> +#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
> +#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
> +#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
> +#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
> +
> +/* Number of PCI buses */
> +extern int pci_bus_cnt;
externs should come through header files usually.

> +
> +int pci_config_auto_initialized = 0;
> +
> +/* Configuration setup */
> +struct pci_auto_setup pci_auto_cfg;
> +
> +/* Insert BAR into the sorted resources list. The BARs are sorted on the
> + * BAR size/alignment need.
> + */
> +static void pci_res_insert(struct pci_res **root, struct pci_res *res)
> +{
> +       struct pci_res *curr, *last;
> +       unsigned long curr_size_resulting_boundary, size_resulting_boundary;
> +       unsigned long boundary, size;
> +
> +       res->start = 0;
> +       res->end = 0;
> +       boundary = res->boundary;
> +       size = res->size;
> +
> +       /* Insert the resources depending on the boundary needs
> +        * Normally the boundary=size of the BAR, however when
> +        * PCI bridges are involved the bridge's boundary may be
> +        * smaller that the size due to the fact that a bridge
s/that the/than the

> +        * may have different-sized BARs behind, the largest BAR
> +        * (also the BAR with the largest boundary) will decide
> +        * the alignment need.
> +        */
> +       last = NULL;
> +       curr = *root;
> +
> +       /* Order List after boundary, the boundary is maintained
> +        * when the size is on an equal boundary, normally it is
> +        * but may not be with bridges. So in second hand it is
> +        * sorted after resulting boundary - the boundary after
> +        * the resource.
> +        */
> +       while (curr && (curr->boundary >= boundary)) {
> +               if (curr->boundary == boundary) {
> +                       /* Find Resulting boundary of size */
> +                       size_resulting_boundary = 1;
> +                       while ((size & size_resulting_boundary) == 0)
> +                               size_resulting_boundary =
> +                                       size_resulting_boundary << 1;
> +
> +                       /* Find Resulting boundary of curr->size */
> +                       curr_size_resulting_boundary = 1;
> +                       while ((curr->size & curr_size_resulting_boundary) == 0)
> +                               curr_size_resulting_boundary =
> +                                       curr_size_resulting_boundary << 1;
> +
> +                       if (size_resulting_boundary >=
> +                           curr_size_resulting_boundary)
> +                               break;
> +               }
> +               last = curr;
> +               curr = curr->next;
> +       }
> +
> +       if (last == NULL) {
> +               /* Insert first in list */
> +               res->next = *root;
> +               *root = res;
> +       } else {
> +               last->next = res;
> +               res->next = curr;
> +       }
> +}
> +
> +#ifdef DEBUG
> +void pci_res_list_print(struct pci_res *root)
> +{
> +       if (root == NULL)
> +               return;
> +
> +       printf("RESOURCE LIST:\n");
> +       while (root) {
> +               printf(" SIZE: 0x%08x, BOUNDARY: 0x%08x\n", root->size,
> +                                                               root->boundary);
> +               root = root->next;
> +       }
> +}
> +#endif
> +
> +/* Reorder a size/alignment ordered resources list. The idea is to
> + * avoid unused due to alignment/size restriction.
> + *
> + * NOTE: The first element is always untouched.
> + * NOTE: If less than three elements in list, nothing will be done
> + *
> + * Normally a BAR has the same alignment requirements as the size of the
> + * BAR. However, when bridges are invloved the alignment need may be smaller
s/invloved/involved

> + * that the size, because a bridge resource consist or multiple BARs.
s/that/than

> + * For example, say that a bridge with a 256Mb and a 16Mb BAR is found, then
> + * the alignment is required to be 256Mb but the size 256+16Mb.
> + *
> + * In order to minimize dead space on the bus, the bounadry ordered list
s/bounadry/boundary

> + * is reordered, example:
> + *  BUS0
> + *  |           BUS1
> + *  |------------|
> + *  |            |-- BAR0: SIZE=256Mb, ALIGNMENT=256MB
> + *  |            |-- BAR1: SIZE=16Mb, ALIGNMENT=16MB
> + *  |            |
> + *  |            |
> + *  |            |
> + *  |            |          BUS2 (BAR_BRIDGE1: SIZE=256+16, ALIGNEMENT=256)
> + *  |            |----------|
> + *  |            |          |-- BAR2: SIZE=256Mb, ALIGNMENT=256Mb
> + *  |            |          |-- BAR3: SIZE=16Mb, ALIGNMENT=16MB
> + *
> + * A alignement/boundary ordered list of BUS1 will look like:
s/A alignement/An alignment

> + *     - BAR_BRIDGE1
> + *     - BAR0            (ALIGMENT NEED 256Mb)
> + *     - BAR1
> + *
> + * However, Between BAR_BRIDGE1 and BAR0 will be a unused hole of 256-16Mb.
> + * We can put BAR1 before BAR0 to avoid the problem.
> + */
> +static void pci_res_reorder(struct pci_res *root)
> +{
> +       struct pci_res *curr, *last, *curr2, *last2;
> +       unsigned int start, start_next, hole_size, hole_boundary;
> +
> +       if (root == NULL)
> +               return;
> +
> +       /* Make up a start address with the boundary of the
> +        * First element.
> +        */
> +       start = root->boundary + root->size;
> +       last = root;
> +       curr = root->next;
> +       while (curr) {
> +
> +               /* Find start address of resource */
> +               start_next = (start + (curr->boundary - 1)) &
> +                                       ~(curr->boundary - 1);
> +
> +               /* Find hole size, the unsed space inbetween last resource
s/inbetween/in between

> +                *and next */
/s/*and/* and

> +               hole_size = start_next - start;
> +
> +               /* Find Boundary of START */
> +               hole_boundary = 1;
> +               while ((start & hole_boundary) == 0)
> +                       hole_boundary = hole_boundary<<1;
> +
> +               /* Detect dead hole */
> +               if (hole_size > 0) {
> +                       /* Step through list and try to find a resource that
> +                        * can fit into hole. Take into account hole start
> +                        * boundary and hole size.
> +                        */
> +                       last2 = curr;
> +                       curr2 = curr->next;
> +                       while (curr2) {
> +                               if ((curr2->boundary <= hole_boundary) &&
> +                                        (curr2->size <= hole_size)) {
> +                                       /* Found matching resource. Move it
> +                                        * first in the hole. Then rescan, now
> +                                        * that the hole has changed in
> +                                        * size/boundary.
> +                                        */
> +                                       last2->next = curr2->next;
> +                                       curr2->next = curr;
> +                                       last->next = curr2;
> +
> +                                       /* New Start address */
> +                                       start_next = (start +
> +                                                    (curr2->boundary - 1)) &
> +                                                    ~(curr2->boundary - 1);
> +                                       /* Since we inserted the resource before
> +                                        * curr we need to re-evaluate curr one
> +                                        * more, more resources may fit into the
> +                                        * shrunken hole.
> +                                        */
> +                                       curr = curr2;
> +                                       break;
> +                               }
> +                               last2 = curr2;
> +                               curr2 = curr2->next;
> +                       }
> +               }
> +
> +               /* No hole or nothing fitted into hole. */
s/fitted/fit

> +               start = start_next;
> +
> +               last = curr;
> +               curr = curr->next;
> +       }
> +}
> +
> +/* Find the total size required in PCI address space needed by a resource list*/
> +static unsigned int pci_res_size(struct pci_res *root)
> +{
> +       struct pci_res *curr;
> +       unsigned int size;
> +
> +       /* Get total size of all resources */
> +       size = 0;
> +       curr = root;
> +       while (curr) {
> +               size = (size + (curr->boundary - 1)) & ~(curr->boundary - 1);
I see this alignment code repeated, you might consider having a macro
for it even if just in this file.

> +               size += curr->size;
> +               curr = curr->next;
> +       }
> +
> +       return size;
> +}
> +
> +#if 0 /* not used for now */
> +/* Free a device and secondary bus if device is a bridge */
> +static void pci_dev_free(struct pci_dev *dev)
> +{
> +       struct pci_dev *subdev;
> +       struct pci_bus *bus;
> +
> +       if (dev->flags & PCI_DEV_BRIDGE) {
> +               bus = (struct pci_bus *)dev;
> +               for (subdev = bus->devs; subdev ; subdev = subdev->next)
> +                       pci_dev_free(dev);
> +       }
> +
> +       free(dev);
> +}
> +#endif
Will it be used later? I don't really care for carrying around
commented-out code.

[...]

> +
> +/* This routine assumes that PCI access library has been successfully
> + * initialized. All information about the PCI bus needed is found in
> + * the argument.
> + *
What argument?

> + * The PCI buses are enumerated as bridges are found, PCI devices are
> + * setup with BARs and IRQs, etc.
> + */
> +int pci_config_auto(void)
> +{
> +       uint32_t end;
> +       uint32_t startmemio, startmem, startio;
> +       struct pci_auto_setup *autocfg = &pci_auto_cfg;
> +#ifdef DEBUG
> +       uint32_t endmemio, endmem, endio;
> +       uint32_t start;
> +#endif
> +
> +       if (pci_config_auto_initialized == 0)
> +               return -1; /* no config given to library */
> +
> +#ifdef DEBUG
> +       DBG("\n--- PCI MEMORY AVAILABLE ---\n");
> +       if (autocfg->mem_size) {
> +               start = autocfg->mem_start;
> +               end = autocfg->mem_start + autocfg->mem_size - 1;
> +               DBG(" MEM AVAIL [0x%08x-0x%08x]\n", start, end);
> +       } else {
> +               /* One big memory space */
> +               DBG(" MEM share the space with MEMIO\n");
> +       }
> +       /* no-prefetchable memory space need separate memory space.
> +        * For example PCI controller maps this region non-cachable.
> +        */
> +       start = autocfg->memio_start;
> +       end = autocfg->memio_start + autocfg->memio_size - 1;
> +       DBG(" MEMIO AVAIL [0x%08x-0x%08x]\n", start, end);
> +       if (autocfg->io_size) {
> +               start = autocfg->io_start;
> +               end = autocfg->io_start + autocfg->io_size - 1;
> +               DBG(" I/O AVAIL [0x%08x-0x%08x]\n", start, end);
> +       } else {
> +               DBG(" I/O Space not available\n");
> +       }
> +#endif
> +
> +       /* Init Host-Bridge */
> +       memset(&pci_hb, 0, sizeof(pci_hb));
> +       pci_hb.dev.flags = PCI_DEV_BRIDGE;
> +       if (autocfg->memio_size <= 0)
> +               return -1;
> +       pci_hb.flags = PCI_BUS_MEMIO;
> +       if (autocfg->mem_size)
> +               pci_hb.flags |= PCI_BUS_MEM;
> +       if (autocfg->io_size)
> +               pci_hb.flags |= PCI_BUS_IO;
> +
> +       /* Find all PCI devices/functions on all buses. The buses will be
> +        * enumrated (assigned a unique PCI Bus ID 0..255).
> +        */
> +       DBG("\n--- PCI SCANNING ---\n");
> +       pci_find_devs(&pci_hb);
> +       pci_bus_cnt = pci_hb.sord + 1;
> +       if (pci_hb.devs == NULL)
> +               return 0;
> +
> +       pci_system_type = PCI_SYSTEM_HOST;
> +
> +       /* Find all resources (MEM/MEMIO/IO BARs) of all devices/functions
> +        * on all buses.
> +        *
> +        * Device resources behind bridges which does not support prefetchable
> +        * memory are already marked as non-prefetchable memory.
> +        * Devices which as I/O resources behind a bridge that do not support
> +        * I/O space are marked DISABLED.
> +        *
> +        * All BARs and Bridge Spaces are disabled after this. Only the ones
> +        * that are allocated an address are initilized later on.
> +        */
> +       DBG("\n\n--- PCI RESOURCES ---\n");
> +       pci_for_each_dev(pci_find_res_dev, 0);
> +
> +       /* Add all device's resources to bus and sort them to fit in the PCI
> +        * Window. The device resources are propagated upwards through bridges
> +        * by adding a "virtual" BAR (boundary != BAR size).
> +        *
> +        * We wait with MEMIO (non-prefetchable memory) resources to after MEM
> +        * resources have been allocated, so that MEM resources can be changed
> +        * into MEMIO resources if not enough space.
> +        */
> +       pci_add_res_bus(&pci_hb, PCI_RES_IO);
> +       pci_add_res_bus(&pci_hb, PCI_RES_MEM);
> +
> +       /* Start assigning found resource according to the sorted order. */
> +
> +       /* Allocate resources to I/O areas */
> +       if (pci_hb.busres[BUS_RES_IO]) {
> +               startio = autocfg->io_start;
> +               end = startio + autocfg->io_size;
> +#ifdef DEBUG
> +               endio =
> +#endif
> +                       pci_alloc_res(&pci_hb, PCI_RES_IO, startio, end);
I might prefer to see the variable always assigned, and then declared
unused if !DEBUG, eg
endio = pci_alloc_res(&pci_hb, PCI_RES_IO, startio, end)
#ifndef DEBUG
  (void) endio;
#endif
You could even aggregate the (void)s down below. Or better yet do some
error checking.

[...]


> diff --git a/cpukit/libpci/pci_cfg_read.c b/cpukit/libpci/pci_cfg_read.c
> new file mode 100644
> index 0000000..2db465d
> --- /dev/null
> +++ b/cpukit/libpci/pci_cfg_read.c
> @@ -0,0 +1,357 @@
> +/*  Read current PCI configuration that bootloader or BIOS has already setup
> + *  and initialize the PCI structures.
> + *
> + *  COPYRIGHT (c) 2010.
> + *  Cobham Gaisler AB.
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.com/license/LICENSE.
> + */
> +
> +#include <rtems.h>
> +#include <stdlib.h>
> +#include <rtems/bspIo.h>
> +#include <pci/cfg.h>
> +#include <pci/access.h>
> +
> +/* PCI Library
> + * (For debugging it might be good to use other functions or the driver's
> + *  directly)
> + */
> +#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
> +#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
> +#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
> +#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
> +#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
> +#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
> +
> +#ifdef DEBUG
> +#define DBG(args...)   printk(args)
> +#else
> +#define DBG(args...)
> +#endif
> +
> +/* Number of buses */
> +extern int pci_bus_cnt;
> +
> +/* The Host Bridge bus is initialized here */
> +extern struct pci_bus pci_hb;
> +
> +static struct pci_dev *pci_dev_create(int isbus)
> +{
> +       void *ptr;
> +       int size;
> +
> +       if (isbus)
> +               size = sizeof(struct pci_bus);
> +       else
> +               size = sizeof(struct pci_dev);
> +
> +       ptr = malloc(size);
> +       if (!ptr)
> +               rtems_fatal_error_occurred(RTEMS_NO_MEMORY);
> +       memset(ptr, 0, size);
> +       return ptr;
> +}
This function is identical to one in pci_cfg_auto.c?

> +
> +/* Check if address is accessible from host */
> +static int pci_read_addressable(struct pci_dev *dev, struct pci_res *res)
> +{
> +       struct pci_bus *bus = dev->bus;
> +       int type = res->flags & PCI_RES_TYPE_MASK;
> +       struct pci_res *range0, *range1;
> +
> +       if (type == PCI_BUS_IO && (bus->flags & PCI_BUS_IO) == 0)
> +               return 0;
> +
> +       /* Assume that host bridge can access all */
> +       if (bus->pri == 0)
> +               return 1;
> +
> +       range1 = NULL;
> +       switch (type) {
> +       case PCI_RES_IO:
> +               range0 = &bus->dev.resources[BRIDGE_RES_IO];
> +               break;
> +       case PCI_RES_MEM:
> +               range1 = &bus->dev.resources[BRIDGE_RES_MEM];
> +       default:
> +       case PCI_RES_MEMIO:
> +               range0 = &bus->dev.resources[BRIDGE_RES_MEMIO];
> +               break;
> +       }
> +       if ((res->start >= range0->start) && (res->end <= range0->end)) {
> +               return pci_read_addressable(&bus->dev, range0);
> +       } else if (range1 && (res->start >= range1->start) &&
> +                       (res->end <= range1->end)) {
> +               return pci_read_addressable(&bus->dev, range1);
> +       }
> +
> +       return 0;
> +}
> +
> +static void pci_read_bar(struct pci_dev *dev, int bar)
> +{
This code is very similar to pci_find_bar(). Consider sharing some of
it if there is no good reason to keep them separate.

> +       uint32_t orig, size, mask;
> +       struct pci_res *res = &dev->resources[bar];
> +       pci_dev_t pcidev = dev->busdevfun;
> +       int ofs;
> +#ifdef DEBUG
> +       char *str;
> +#define DBG_SET_STR(str, val) str = (val)
> +#else
> +#define DBG_SET_STR(str, val)
> +#endif
> +
> +       DBG("Bus: %x, Slot: %x, function: %x, bar%d\n",
> +               PCI_DEV_EXPAND(pcidev), bar);
> +
> +       res->bar = bar;
> +       if (bar == DEV_RES_ROM) {
> +               if (dev->flags & PCI_DEV_BRIDGE)
> +                       ofs = PCI_ROM_ADDRESS1;
> +               else
> +                       ofs = PCI_ROM_ADDRESS;
> +       } else {
> +               ofs = PCI_BASE_ADDRESS_0 + (bar << 2);
> +       }
> +
> +       PCI_CFG_R32(pcidev, ofs, &orig);
> +       PCI_CFG_W32(pcidev, ofs, 0xffffffff);
> +       PCI_CFG_R32(pcidev, ofs, &size);
> +       PCI_CFG_W32(pcidev, ofs, orig);
> +
> +       if (size == 0 || size == 0xffffffff)
> +               return;
> +       if (bar == DEV_RES_ROM) {
> +               mask = PCI_ROM_ADDRESS_MASK;
> +               DBG_SET_STR(str, "ROM");
> +               if (dev->bus->flags & PCI_BUS_MEM)
> +                       res->flags = PCI_RES_MEM;
> +               else
> +                       res->flags = PCI_RES_MEMIO;
> +       } else if (((size & 0x1) == 0) && (size & 0x6)) {
> +               /* unsupported Memory type */
> +               return;
> +       } else {
> +               mask = ~0xf;
> +               if (size & 0x1) {
> +                       /* I/O */
> +                       mask = ~0x3;
> +                       res->flags = PCI_RES_IO;
> +                       DBG_SET_STR(str, "I/O");
> +                       if (size & 0xffff0000)
> +                               res->flags |= PCI_RES_IO32;
> +                       /* Limit size of I/O space to 256 byte */
> +                       size |= 0xffffff00;
Is this really supposed to be |=?

[...]

> diff --git a/cpukit/libpci/pci_cfg_static.c b/cpukit/libpci/pci_cfg_static.c
> new file mode 100644
> index 0000000..d7d4321
> --- /dev/null
> +++ b/cpukit/libpci/pci_cfg_static.c
> @@ -0,0 +1,157 @@
> +/*  PCI (Static) Configuration Library
> + *
> + *  COPYRIGHT (c) 2010.
> + *  Cobham Gaisler AB.
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.com/license/LICENSE.
> + */
> +
> +/*
> + * The Host Bridge bus must be declared by user. It contains the static
> + * configuration used to setup the devices/functions.
> + */
> +
> +/* Configure headers */
> +#define PCI_CFG_STATIC_LIB
> +
> +#include <stdlib.h>
> +#include <pci.h>
> +#include <pci/access.h>
> +#include <pci/cfg.h>
> +
> +#define PCI_CFG_R8(dev, args...) pci_cfg_r8(dev, args)
> +#define PCI_CFG_R16(dev, args...) pci_cfg_r16(dev, args)
> +#define PCI_CFG_R32(dev, args...) pci_cfg_r32(dev, args)
> +#define PCI_CFG_W8(dev, args...) pci_cfg_w8(dev, args)
> +#define PCI_CFG_W16(dev, args...) pci_cfg_w16(dev, args)
> +#define PCI_CFG_W32(dev, args...) pci_cfg_w32(dev, args)
> +
> +/* Number of buses */
> +extern int pci_bus_cnt;
> +
> +/* Enumrate one bus if device is a bridge, and all it's subordinate buses */
> +static int pci_init_dev(struct pci_dev *dev, void *unused)
> +{
The code in this function is very similar to that in pci_find_devs(),
which also seems to share some code with pci_read_devs(). It might be
sensible to refactor/reduce some of this copy-paste.

[...]


> diff --git a/doc/user/c_user.texi b/doc/user/c_user.texi
> index 2ff47bf..bdf0cd5 100644
> --- a/doc/user/c_user.texi
> +++ b/doc/user/c_user.texi
> @@ -107,6 +107,7 @@
>  * Configuring a System::
>  * Multiprocessing Manager::
>  * Symmetric Multiprocessing Services::
> +* PCI Library::
>  * Stack Bounds Checker::
>  * CPU Usage Statistics::
>  * Object Services::
> @@ -152,6 +153,7 @@
>  @include conf.texi
>  @include mp.texi
>  @include smp.texi
> + at include libpci.texi
>  @include stackchk.texi
>  @include cpuuse.texi
>  @include object.texi
> diff --git a/doc/user/conf.t b/doc/user/conf.t
> index dc10816..0c5ab32 100644
> --- a/doc/user/conf.t
> +++ b/doc/user/conf.t
> @@ -5237,6 +5237,59 @@ uses the Ada run-time.
>  None.
>
>  @c
> + at c === PCI Library ===
> + at c
> + at section PCI Library
> +
> +This section defines the system configuration paramters supported
s/paramters/parameters

> +by @code{rtems/confdefs.h} related to configuring the PCI Library
> +for RTEMS.
> +
> +The PCI Library startup behaviour can be configured in four diffent
s/diffent/different

> +ways depending on how @code{CONFIGURE_PCI_CONFIG_LIB} is defined:
> +
> + at itemize @bullet
> + at findex PCI_LIB_AUTO
> + at item @code{PCI_LIB_AUTO} is used to enable the PCI auto configuration
> +software. PCI will be automatically probed, PCI buses enumerated, all
> +devices and bridges will be initialized using Plug & Play software
> +routines. The PCI device tree will be populated based on the PCI devices
> +found in the system, PCI devices will be configured by allocating address
> +region resources automatically in PCI space according to the BSP or host
> +bridge driver set up.
> +
> + at findex PCI_LIB_READ
> + at item @code{PCI_LIB_READ} is used to enable the PCI read configuration
> +software. The current PCI configuration is read to create the RAM
> +representation (the PCI device tree) of the PCI devices present. PCI devices
> +are assumed to already have been initialized and PCI buses enumrated, it is
s/enumrated/enumerated

> +therefore required that a BIOS or a boot loader has set up configuration space
> +prior to booting into RTEMS.
> +
> + at findex PCI_LIB_STATIC
> + at item @code{PCI_LIB_STATIC} is used to enable the PCI static configuration
> +software. The user provides a PCI tree with information how all PCI devices
s/how/about how

> +are to be configured at compile time by linking in a custom
> + at code{struct pci_bus pci_hb} tree. The static PCI library will not probe PCI
> +for devices, instead it will assume that all devices defined by the user is
s/is/are

> +present, it will enumerate the PCI buses and configure all PCI devices in
> +static configuration accordingly. Since probe and allocation software is not
> +needed the startup is faster, have smaller footprint and does not require
s/have/has

> +dynamic memory allocation.
> +
> + at findex PCI_LIB_PERIPHERAL
> + at item @code{PCI_LIB_PERIPHERAL} is used to enable the PCI peripheral
> +configuration. It is similar to @code{PCI_LIB_STATIC}, but is will never write
s/is will/it will

> +the configuration to the PCI devices since PCI peripherals are not allowed to
> +access PCI configuration space.
> +
> + at end itemize
> +
> +Note that selecting PCI_LIB_STATIC or PCI_LIB_PERIPHERAL but not defining
> + at code{pci_hb} will reuslt in link errors. Note also that in these modes
> +Plug & Play is not performed.
> +
> + at c
>  @c === Go Tasks ===
>  @c
>  @section Go Tasks
> diff --git a/doc/user/libpci.t b/doc/user/libpci.t
> new file mode 100644
> index 0000000..1eaca42
> --- /dev/null
> +++ b/doc/user/libpci.t
> @@ -0,0 +1,409 @@
> + at c
> + at c  COPYRIGHT (c) 2011
> + at c  Aeroflex Gaisler AB
> + at c  All rights reserved.
> + at c
> + at c  $Id: libpci.t,v v.vv xxxx/yy/zz xx:yy:zz ? Exp $
> + at c
> +
> + at chapter PCI Library
> +
> + at cindex libpci
> +
> + at section Introduction
> +
> +The Peripheral Component Interconnect (PCI) bus is a very common computer
> +bus architecture that is found in almost every PC today. The PCI bus is
> +normally located at the motherboard where some PCI devices are soldered
> +directly onto the PCB and expansion slots allows the user to add custom
> +devices easily. There is a wide range of PCI hardware available implementing
> +all sorts of interfaces and functions.
> +
> +This section describes the PCI Library available in RTEMS used to access the
> +PCI bus in a portable way across computer architectures supported by RTEMS.
> +
> +The PCI Library aims to be compatible with PCI 2.3 with a couple of
> +limitations, for example there is no support for hot-plugging, 64-bit
> +memory space and cardbus bridges.
> +
> +In order to support different architectures and with small foot-print embedded
> +systems in mind the PCI Library offers four different configuration options
> +listed below. It is selected during compile time by defining the appropriate
> +macros in confdefs.h. It is also possible to enable NONE (No Configuration)
> +which can be used for debuging PCI access functions.
s/debugin/debugging

Is this true? It looks like "none" gives an error in confdefs.h.

> + at itemize @bullet
> + at item Auto Configuration (do Plug & Play)
> + at item Read Configuration (read BIOS or boot loader configuration)
> + at item Static Configuration (write user defined configuration)
> + at item Peripheral Configuration (no access to cfg-space)
> + at end itemize
> +
> + at section Background
> +
> +The PCI bus is constructed in a way where on-board devices and devices
> +in expansion slots can be automatically found (probed) and configured
> +using Plug & Play completely implemented in software. The bus is set up once
> +during boot up. The Plug & Play information can be read and written from
> +PCI configuration space. A PCI device is identified in configuration space by
> +a unique bus, slot and function number. Each PCI slot can have up to 8
> +functions and interface to another PCI sub-bus by implementing a PCI-to-PCI
> +bridge according to the PCI Bridge Architecture specification.
> +
> +Using the unique [bus:slot:func] any device can be configured regardless how PCI
s/how/of how

> +is currently set up as long as all PCI buses are enumerated correctly. The
> +enumration is done during probing, all bridges are given a bus numbers in
s/enumration/enumeration
s/numbers/number

> +order for the bridges to respond to accesses from both directions. The PCI
> +library can assign address ranges to which a PCI device should respond using
> +Plug & Play technique or a static user defined configuration. After the
> +configuration has been performed the PCI device drivers can find devices by
> +the read-only PCI Class type, Vendor ID and Device ID information found in
> +configuration space for each device.
> +
> +In some systems there is a boot loader or BIOS which have already configured
> +all PCI devices, but on embedded targets it is quite common that there is no
> +BIOS or boot loader, thus RTEMS must configure the PCI bus. Only the PCI host
> +may do configuration space access, the host driver or BSP is responsible to
> +translate the [bus:slot:func] into a valid PCI configuration space access.
> +
> +If the target is not a host, but a peripheral, configuration space can not be
> +accessed, the peripheral is set up by the host during start up. In complex
> +embedded PCI systems the peripheral may need to access other PCI boards than
> +then host. In such systems a custom (static) configuration of both the host
s/then/the

> +and peripheral may be a convenient solution.
> +
> +The PCI bus defines four interrupt signals INTA#..INTD#. The interrupt signals
> +must be mapped into a system interrupt/vector, it is up to the BSP or host
> +driver to know the mapping, however the BIOS or boot loader may use the
> +8-bit read/write "Interrupt Line" register to pass the knowledge along to the
> +OS.
> +
> +
> + The PCI standard
> +defines and recommends that the backplane route the interupt lines in a
> +systematic way, however in
> +
Incomplete paragraph here.

> + at subsection Software Components
> +
> +The PCI library is located in cpukit/libpci, it consists of different parts:
> + at itemize @bullet
> + at item PCI Host bridge driver interface
> + at item Configuration routines
> + at item Access (Configuration, I/O and Memory space) routines
> + at item Interrupt routines (implemented by BSP)
> + at item Print routines
> + at item Static/peripheral configuration creation
> + at item PCI shell command
> + at end itemize
> +
> + at subsection PCI Configuration
> +
> +During start up the PCI bus must be configured in order for host and peripherals
> +to access one another using Memory or I/O accesses and that interrupts are
> +properly handled. Three different spaces are defined and mapped separately:
> + at enumerate
> + at item I/O space (IO)
> + at item non-prefetchable Memory space (MEMIO)
> + at item prefetchable Memory space (MEM)
> + at end enumerate
> +
> +Regions of the same type (I/O or Memory) may not overlap which is guaranteed
> +by the software. MEM regions may be mapped into MEMIO regions, but MEMIO
> +regions can not be mapped into MEM, for that could lead to prefetching of
> +registers. The interrupt pin which a board is driving can be read out from
> +PCI configuration space, however it is up to software to know how interrupt
> +signals are routed between PCI-to-PCI bridges and how PCI INT[A..D]# pins are
> +mapped to system IRQ. In systems where previous software (boot loader or BIOS)
> +has already set up this the configuration overwritten or simply read out.
s/overwritten/is overwritten

> +
> +In order to support different configuration methods the following configuration
> +libraries are available can selectable by the user:
delete "available can"

> + at itemize @bullet
> + at item Auto Configuration (run Plug & Play software)
> + at item Read Configuration (relies on a boot loader or BIOS)
> + at item Static Configuration (write user defined setup, no Plug & Play)
> + at item Peripheral Configuration (user defined setup, no access to configuration space)
> + at end itemize
> +
> +A host driver can be made to support all three configuration methods, or any
> +combination. It may be defined by the BSP which approach is used.
> +
> +The configuration software is called from the PCI driver (pci_config_init()).
> +
> +Regardless of configuration method a PCI device tree is created in RAM during
> +initialization, the tree can be accessed to find devices and resources without
> +accessing configuration space later on. The user is responsible to create the
> +device tree at compile time when using the static/peripheral method.
> +
> +
> + at subsubsection RTEMS Configuration selection
> +
> +The active configuration method can be selected at compile time in the same
> +way as other project parameters by including rtems/confdefs.h and setting
> + at itemize @bullet
> + at item CONFIGURE_INIT
> + at item RTEMS_PCI_CONFIG_LIB
> + at item CONFIGURE_PCI_LIB = PCI_LIB_(AUTO,STATIC,READ,PERIPHERAL)
> + at end itemize
> +
> +See the RTEMS configuration section how to setup the PCI library.
> +
> +
> + at subsubsection Auto Configuration
> +
> +The auto configuration software enumerate PCI buses and initializes all PCI
s/enumerate/enumerates

> +devices found using Plug & Play. The auto configuration software requires
> +that a configuration setup has been registered by the driver or BSP in order
> +to setup the I/O and Memory regions at the correct address ranges. PCI
> +interrupt pins can optionally be routed over PCI-to-PCI bridges and mapped
> +to a system interrupt number. Resources are sorted by size and required
> +alignment, unused "dead" space may be created when PCI bridges are present
> +due to the PCI bridge window size does not equal the alignment, to cope with
> +that resources are reordered to fit smaller BARs into the dead space to minimize
BARs should probably be defined before used.

> +the PCI space required. If a BAR or ROM register can not be allocated a PCI
> +address region (due to too few resources available) the register will be given
> +the value of pci_invalid_address which defaults to 0.
> +
> +The auto configuration routines support:
> + at itemize @bullet
> + at item PCI 2.3
> + at item Little and big endian PCI bus
> + at item one I/O 16 or 32-bit range (IO)
> + at item memory space (MEMIO)
> + at item prefetchable memory space (MEM), if not present MEM will be mapped into
> +      MEMIO
> + at item multiple PCI buses - PCI-to-PCI bridges
> + at item standard BARs, PCI-to-PCI bridge BARs, ROM BARs
> + at item Interrupt routing over bridges
> + at item Interrupt pin to system interrupt mapping
> + at end itemize
> +
> +Not supported:
> + at itemize @bullet
> + at item hot-pluggable devices
> + at item Cardbus bridges
> + at item 64-bit memory space
> + at item 16-bit and 32-bit I/O address ranges at the same time
> + at end itemize
> +
> +In PCI 2.3 there may exist I/O BARs that must be located at the low 64kBytes
> +address range, in order to support this the host driver or BSP must make sure
> +that I/O addresses region is within this region.
> +
> +
> + at subsubsection Read Configuration
> +
> +When a BIOS or boot loader already has setup the PCI bus the configuration can
> +be read directly from the PCI resource registers and buses are already
> +enumerated, this is a much simpler approach than configuring PCI ourselves. The
> +PCI device tree is automatically created based on the current configuration and
> +devices present. After initialization is done there is no difference between
> +the auto or read configuration approaches.
> +
> +
> + at subsubsection Static Configuration
> +
> +To support custom configurations and small-footprint PCI systems, the user may
> +provide the PCI device tree which contains the current configuration. The
> +PCI buses are enumerated and all resources are written to PCI devices during
> +initialization. When this approach is selected PCI boards must be located at
> +the same slots every time and devices can not be removed or added, Plug & Play
> +is not performed. Boards of the same type may of course be exchanged.
> +
> +The user can create a configuration by calling pci_cfg_print() on a running
> +system that has had PCI setup by the auto or read configuration routines, it
> +can be called from the PCI shell command. The user must provide the PCI device
> +tree named pci_hb.
> +
> +
> + at subsubsection Peripheral Configuration
> +
> +On systems where a peripheral PCI device needs to access other PCI devices than
> +the host the peripheral configuration approach may be handy. Most PCI devices
> +answers on the PCI host's requests and start DMA accesses into the Hosts memory,
> +however in some complex systems PCI devices may want to access other devices
> +on the same bus or at another PCI bus.
> +
> +A PCI peripheral is not allowed to do PCI configuration cycles, which means that
> +is must either rely on the host to give it the addresses it needs, or that the
s/is/it

> +addresses are predefined.
> +
> +This configuration approach is very similar to the static option, however the
> +configuration is never written to PCI bus, instead it is only used for drivers
> +to find PCI devices and resources using the same PCI API as for the host
> +
> +
> + at subsection PCI Access
> +
> +The PCI access routines are low-level routines provided for drivers,
> +configuration software, etc. in order to access different regions in a way
> +not dependent upon the host driver, BSP or platform.
> + at itemize @bullet
> + at item PCI configuration space
> + at item PCI I/O space
> + at item Registers over PCI memory space
> + at item Translate PCI address into CPU accessible address and vice verse
s/verse/versa

> + at end itemize
> +
> +By using the access routines drivers can be made portable over different
> +architectures. The access routines take the architecture endianness into
> +consideration and let the host driver or BSP implement I/O space and
> +configuration space access.
> +
> +Some non-standard hardware may also define the PCI bus big-endian, for example
> +the LEON2 AT697 PCI host bridge and some LEON3 systems may be configured that
> +way. It is up to the BSP to set the appropriate PCI endianness on compile time
> +(BSP_PCI_BIG_ENDIAN) in order for inline macros to be correctly defined.
> +Another possibility is to use the function pointers defined by the access
> +layer to implement drivers that support "run-time endianness detection".
> +
> +
> + at subsubsection Configuration space
> +
> +Configuration space is accessed using the routines listed below. The
> +pci_dev_t type is used to specify a specific PCI bus, device and function. It
> +is up to the host driver or BSP to create a valid access to the requested
> +PCI slot. Requests made to slots that is not supported by hardware should
s/is/are

> +result in PCISTS_MSTABRT and/or data must be ignored (writes) or 0xffffffff
> +is always returned (reads).
> +
> + at example
> +  /* Configuration Space Access Read Routines */
> +  extern int pci_cfg_r8(pci_dev_t dev, int ofs, uint8_t *data);
> +  extern int pci_cfg_r16(pci_dev_t dev, int ofs, uint16_t *data);
> +  extern int pci_cfg_r32(pci_dev_t dev, int ofs, uint32_t *data);
> +
> +  /* Configuration Space Access Write Routines */
> +  extern int pci_cfg_w8(pci_dev_t dev, int ofs, uint8_t data);
> +  extern int pci_cfg_w16(pci_dev_t dev, int ofs, uint16_t data);
> +  extern int pci_cfg_w32(pci_dev_t dev, int ofs, uint32_t data);
> + at end example
> +
> +
> + at subsubsection I/O space
> +
> +The BSP or driver provide special routines in order to access I/O space. Some
> +architectures have a special instruction accessing I/O space, others have it
> +mapped into a "PCI I/O window" in the standard address space accessed by the
> +CPU. The window size may vary and must be taken into consideration by the
> +host driver. The below routines must be used to access I/O space. The address
> +given to the functions is not the PCI I/O addresses, the caller must have
> +translated PCI I/O addresses (available in the PCI BARs) into a BSP or host
> +driver custom address, see @ref{Access functions} how addresses are
s/how/for how

> +translated.
> +
> + at example
> +/* Read a register over PCI I/O Space */
> +extern uint8_t pci_io_r8(uint32_t adr);
> +extern uint16_t pci_io_r16(uint32_t adr);
> +extern uint32_t pci_io_r32(uint32_t adr);
> +
> +/* Write a register over PCI I/O Space */
> +extern void pci_io_w8(uint32_t adr, uint8_t data);
> +extern void pci_io_w16(uint32_t adr, uint16_t data);
> +extern void pci_io_w32(uint32_t adr, uint32_t data);
> + at end example
> +
> +
> + at subsubsection Registers over Memory space
> +
> +PCI host bridge hardware normally swap data accesses into the endianness of the
> +host architecture in order to lower the load of the CPU, peripherals can do DMA
> +without swapping. However, the host controller can not separate a standard
> +memory access from a memory access to a register, registers may be mapped into
> +memory space. This leads to register content being swapped, which must be
> +swapped back. The below routines makes it possible to access registers over PCI
> +memory space in a portable way on different architectures, the BSP or
> +architecture must provide necessary functions in order to implement this.
> +
> + at example
> +  static inline uint16_t pci_ld_le16(volatile uint16_t *addr);
> +  static inline void pci_st_le16(volatile uint16_t *addr, uint16_t val);
> +  static inline uint32_t pci_ld_le32(volatile uint32_t *addr);
> +  static inline void pci_st_le32(volatile uint32_t *addr, uint32_t val);
> +  static inline uint16_t pci_ld_be16(volatile uint16_t *addr);
> +  static inline void pci_st_be16(volatile uint16_t *addr, uint16_t val);
> +  static inline uint32_t pci_ld_be32(volatile uint32_t *addr);
> +  static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val);
> + at end example
> +
> +In order to support non-standard big-endian PCI bus the above pci_* functions
> +is required, pci_ld_le16 != ld_le16 on big endian PCI buses.
> +
> +
> + at subsubsection Access functions
> +
> +The PCI Access Library can provide device drivers with function pointers
> +executing the above Configuration, I/O and Memory space accesses. The
> +functions have the same arguments and return values as the as the above
s/as the as the/as the

> +functions.
> +
> +The pci_access_func() function defined below can be used to get a function
> +pointer of a specific access type.
> +
> + at example
> +  /* Get Read/Write function for accessing a register over PCI Memory Space
> +   * (non-inline functions).
> +   *
> +   * Arguments
> +   *  wr             0(Read), 1(Write)
> +   *  size           1(Byte), 2(Word), 4(Double Word)
> +   *  func           Where function pointer will be stored
> +   *  endian         PCI_LITTLE_ENDIAN or PCI_BIG_ENDIAN
> +   *  type           1(I/O), 3(REG over MEM), 4(CFG)
> +   *
> +   * Return
> +   *  0              Found function
> +   *  others         No such function defined by host driver or BSP
> +   */
> +  int pci_access_func(int wr, int size, void **func, int endian, int type);
> + at end example
> +
> +PCI devices drivers may be written to support run-time detection of endianess,
s/devices/device

> +this is mosly for debugging or for development systems. When the product is
> +finally deployed macros switch to using the inline functions instead which
> +have been configured for the correct endianness.
> +
> +
> + at subsubsection PCI address translation
> +
> +When PCI addresses, both I/O and memory space, is not mapped 1:1 address
> +translation before access is needed. If drivers read the PCI resources directly
> +using configuration space routines or in the device tree, the addresses given
> +are PCI addresses. The below functions can be used to translate PCI addresses
> +into CPU accessible addresses or vise versa, translation may be different for
s/vise/vice

> +different PCI spaces/regions.
> +
> + at example
> +  /* Translate PCI address into CPU accessible address */
> +  static inline int pci_pci2cpu(uint32_t *address, int type);
> +
> +  /* Translate CPU accessible address into PCI address (for DMA) */
> +  static inline int pci_cpu2pci(uint32_t *address, int type);
> + at end example
> +
> +
> + at subsection PCI Interrupt
> +
> +The PCI specification defines four different interrupt lines INTA#..INTD#,
> +the interrupts are low level sensitive which make it possible to support
> +multiple interrupt sources on the same interrupt line. Since the lines are
> +level sensitive the interrupt sources must be acknowledged before clearing the
> +interrupt contoller, or the interrupt controller must be masked. The BSP must
> +provide a routine for clearing/acknowledging the interrupt controller, it is
> +up to the interrupt service routine to acknowledge the interrupt source.
> +
> +The PCI Library relies on the BSP for implementing shared interrupt handling
> +through the BSP_PCI_shared_interrupt_* functions/macros, they must be defined
> +when including bsp.h.
> +
> +PCI device drivers may use the pci_interrupt_ routines in order to call the
> +BSP specific functions in a platform independent way. The PCI interrupt
> +interface has been made similar to the RTEMS IRQ extension so that a BSP can
> +use the standard RTEMS interrupt functions directly.
> +
> +
> + at subsection PCI Shell command
> +
> +The RTEMS shell have a PCI command 'pci' which makes it possible to read/write
s/have/has

> +configuration space, print the current PCI configuration and print out a
> +configuration C-file for the static or peripheral library.
> --
> 1.7.0.4
All done!



More information about the devel mailing list