diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2011-06-23 12:07:48 +0200 |
---|---|---|
committer | Daniel Hellstrom <daniel@gaisler.com> | 2012-03-27 15:19:59 +0200 |
commit | 733f3f88ec3b7ef1226b96b31168fa0c6ae5d8da (patch) | |
tree | 1dbdee991fdaf3aa593e11e516ed83a32e319dc3 /cpukit | |
parent | 23fb2aa174744e23dafb86915f209af8a9cbfbc6 (diff) |
LIBPCI: implemented LD/ST endian non-inline functions, PCI Big Endian support
Diffstat (limited to 'cpukit')
-rw-r--r-- | cpukit/libmisc/shell/main_pci.c | 36 | ||||
-rw-r--r-- | cpukit/libpci/Makefile.am | 4 | ||||
-rw-r--r-- | cpukit/libpci/pci/access.h | 64 | ||||
-rw-r--r-- | cpukit/libpci/pci_access_func.c | 63 | ||||
-rw-r--r-- | cpukit/libpci/pci_access_mem.c | 11 | ||||
-rw-r--r-- | cpukit/libpci/pci_access_mem_be.c | 62 | ||||
-rw-r--r-- | cpukit/libpci/pci_access_mem_le.c | 61 | ||||
-rw-r--r-- | cpukit/libpci/pci_bus.c | 21 | ||||
-rw-r--r-- | cpukit/libpci/pci_bus.h | 76 |
9 files changed, 340 insertions, 58 deletions
diff --git a/cpukit/libmisc/shell/main_pci.c b/cpukit/libmisc/shell/main_pci.c index 54fa4e150d..6306f27e1a 100644 --- a/cpukit/libmisc/shell/main_pci.c +++ b/cpukit/libmisc/shell/main_pci.c @@ -18,6 +18,8 @@ #include <pci.h> #include <pci/cfg.h> #include <pci/access.h> +#include <rtems/endian.h> +#include <bsp.h> /* For PCI endianness config */ #include <rtems.h> #include <rtems/shell.h> @@ -257,10 +259,39 @@ int shell_pci_pciid(int argc, char *argv[], struct shell_pci_modifier *mod) if ((pciid & 0xffff0000) != 0) return -1; - printf(" PCIID: 0x%lx [%x:%x:%x]\n", pciid, PCI_DEV_EXPAND(pciid)); + printf(" PCIID: 0x%lx [%lx:%lx:%lx]\n", pciid, PCI_DEV_EXPAND(pciid)); return 0; } +int pci_summary(void) +{ + char *str; + char *cfglib_strs[5] = {"NONE", "AUTO", "STATIC", "READ", "PERIPHERAL"}; + + if (pci_system_type == PCI_SYSTEM_HOST) + str = "HOST"; + else if (pci_system_type == PCI_SYSTEM_PERIPHERAL) + str = "PERIPHERAL"; + else + str = "UNKNOWN / UNINITIALIZED"; + printf(" SYSTEM: %s\n", str); + + if (pci_config_lib_type > PCI_CONFIG_LIB_PERIPHERAL) { + puts(" Bad configuration library"); + return 1; + } + printf(" CFG LIBRARY: %s\n", cfglib_strs[pci_config_lib_type]); + printf(" NO. PCI BUSES: %d buses\n", pci_bus_count()); + printf(" PCI ENDIAN: %s\n", pci_endian ? "Big" : "Little"); +#if (CPU_LITTLE_ENDIAN == TRUE) + puts(" MACHINE ENDIAN: Little"); +#else + puts(" MACHINE ENDIAN: Big"); +#endif + + return 0; +} + const char pci_usage_str[] = " usage:\n" " pci ls [bus:dev:fun|PCIID] List one or all devices\n" @@ -329,7 +360,8 @@ int rtems_shell_main_pci( int rc; if (argc < 2) { - usage(); + /* without arguments */ + pci_summary(); rc = 0; } else if ((mod=shell_pci_find_modifier(argv[1])) != NULL) { rc = mod->func(argc, argv, mod); diff --git a/cpukit/libpci/Makefile.am b/cpukit/libpci/Makefile.am index 336f33b650..5c05c75283 100644 --- a/cpukit/libpci/Makefile.am +++ b/cpukit/libpci/Makefile.am @@ -18,7 +18,11 @@ include_pci_HEADERS = pci/access.h pci/cfg.h \ noinst_LIBRARIES = libpci.a libpci_a_SOURCES = pci_access.c +libpci_a_SOURCES += pci_access_func.c libpci_a_SOURCES += pci_access_io.c +libpci_a_SOURCES += pci_access_mem.c +libpci_a_SOURCES += pci_access_mem_be.c +libpci_a_SOURCES += pci_access_mem_le.c libpci_a_SOURCES += pci_cfg.c libpci_a_SOURCES += pci_cfg_auto.c libpci_a_SOURCES += pci_cfg_print_code.c diff --git a/cpukit/libpci/pci/access.h b/cpukit/libpci/pci/access.h index 6b71365721..4f57192f2d 100644 --- a/cpukit/libpci/pci/access.h +++ b/cpukit/libpci/pci/access.h @@ -42,7 +42,9 @@ struct pci_cfg_ops { int (*write32)(pci_dev_t dev, int ofs, uint32_t data); }; -/* Read a register over PCI I/O Space, and swap it if necessary */ +/* Read a register over PCI I/O Space, and swap it if necessary (due to + * PCI endianness) + */ struct pci_io_ops { uint8_t (*read8)(uint8_t *adr); uint16_t(*read16)(uint16_t *adr); @@ -52,6 +54,31 @@ struct pci_io_ops { void (*write32)(uint32_t *adr, uint32_t data); }; +/* Read a register over PCI Memory Space (non-prefetchable memory), and + * swap it if necessary (due to PCI endianness) + */ +struct pci_memreg_ops { + uint8_t (*ld8)(uint8_t *adr); + void (*st8)(uint8_t *adr, uint8_t data); + + uint16_t(*ld_le16)(uint16_t *adr); + void (*st_le16)(uint16_t *adr, uint16_t data); + uint16_t(*ld_be16)(uint16_t *adr); + void (*st_be16)(uint16_t *adr, uint16_t data); + + uint32_t (*ld_le32)(uint32_t *adr); + void (*st_le32)(uint32_t *adr, uint32_t data); + uint32_t (*ld_be32)(uint32_t *adr); + void (*st_be32)(uint32_t *adr, uint32_t data); +}; + +typedef uint8_t (*pci_ld8_t)(uint8_t *adr); +typedef void (*pci_st8_t)(uint8_t *adr, uint8_t data); +typedef uint16_t(pci_ld16_t)(uint16_t *adr); +typedef void (*pci_st16_t)(uint16_t *adr, uint16_t data); +typedef uint32_t (*pci_ld32_t)(uint32_t *adr); +typedef void (*pci_st32_t)(uint32_t *adr, uint32_t data); + struct pci_access_drv { /* Configuration */ struct pci_cfg_ops cfg; @@ -59,6 +86,15 @@ struct pci_access_drv { /* I/O Access operations */ struct pci_io_ops io; + /* Registers over Memory Access operations. Note that these funcs + * are only for code that need to be compatible with both Big-Endian + * and Little-Endian PCI bus or for some other reason need function + * pointers to access functions. Normally drivers use the inline + * functions for Registers-over-Memory access to avoid extra function + * call. + */ + struct pci_memreg_ops *memreg; + /* Translate from PCI address to CPU address (dir=0). Translate * CPU address to PCI address (dir!=0). The address will can be * used to perform I/O access or memory access by CPU or PCI DMA @@ -142,13 +178,13 @@ static inline int pci_pci2cpu(uint32_t *address, int type) return pci_access_ops.translate(address, type, 0); } -/* Get Translate CPU accessible address into PCI DMA address */ +/* Get Translate CPU accessible address into PCI address (for DMA) */ static inline int pci_cpu2pci(uint32_t *address, int type) { return pci_access_ops.translate(address, type, 1); } -/*** Read a register over PCI Memory Space ***/ +/*** Read/Write a register over PCI Memory Space ***/ static inline uint8_t pci_ld8(volatile uint8_t *addr) { @@ -250,6 +286,28 @@ static inline void pci_st_be32(volatile uint32_t *addr, uint32_t val) #endif +/* 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 + */ +extern int pci_access_func(int wr, int size, void **func, int endian, int type); + +/* Predefined functions for Host drivers or BSPs that define the + * register-over-memory space functions operations. + */ +extern struct pci_memreg_ops pci_mem_le_ops; /* For Little-Endian PCI bus */ +extern struct pci_memreg_ops pci_mem_be_ops; /* For Big-Endian PCI bus */ + #ifdef __cplusplus } #endif diff --git a/cpukit/libpci/pci_access_func.c b/cpukit/libpci/pci_access_func.c new file mode 100644 index 0000000000..5ef1a4d223 --- /dev/null +++ b/cpukit/libpci/pci_access_func.c @@ -0,0 +1,63 @@ +#include <pci.h> + +/* Get PCI I/O or Configuration space access function */ +static int pci_ioc_func(int wr, int size, void **func, void **ops) +{ + int ofs; + + ofs = 0; + if (wr) + ofs += 3; + if (size == 4) + size = 3; + ofs += (size & 0x3) - 1; + if (ops[ofs] == NULL) + return -1; + if (func) + *func = ops[ofs]; + return 0; +} + +/* Get Registers-over-Memory Space access function */ +static int pci_memreg_func(int wr, int size, void **func, int endian) +{ + void **ops; + int ofs = 0; + + ops = (void **)pci_access_ops.memreg; + if (!ops) + return -1; + + if (size == 2) + ofs += 2; + else if (size == 4) + ofs += 6; + + if (size != 1 && endian == PCI_BIG_ENDIAN) + ofs += 2; + + if (wr) + ofs += 1; + + if (ops[ofs] == NULL) + return -1; + if (func) + *func = ops[ofs]; + return 0; +} + +/* Get function pointer from Host/BSP driver definitions */ +int pci_access_func(int wr, int size, void **func, int endian, int type) +{ + switch (type) { + default: + case 2: /* Memory Space - not implemented */ + return -1; + case 1: /* I/O space */ + return pci_ioc_func(wr, size, func, (void**)&pci_access_ops.cfg); + case 3: /* Registers over Memory space */ + return pci_memreg_func(wr, size, func, endian); + case 4: /* Configuration space */ + return pci_ioc_func(wr, size, func, (void**)&pci_access_ops.io); + } +} diff --git a/cpukit/libpci/pci_access_mem.c b/cpukit/libpci/pci_access_mem.c new file mode 100644 index 0000000000..dcdd0a6a15 --- /dev/null +++ b/cpukit/libpci/pci_access_mem.c @@ -0,0 +1,11 @@ +#include <pci.h> + +uint8_t pci_mem_ld8(uint8_t *adr) +{ + return *adr; +} + +void pci_mem_st8(uint8_t *adr, uint8_t data) +{ + *adr = data; +} diff --git a/cpukit/libpci/pci_access_mem_be.c b/cpukit/libpci/pci_access_mem_be.c new file mode 100644 index 0000000000..0746588d13 --- /dev/null +++ b/cpukit/libpci/pci_access_mem_be.c @@ -0,0 +1,62 @@ +/* Registers-over-Memory Space - Generic Big endian PCI bus definitions */ + +#include <pci.h> + +/* Same for Little and Big endian PCI buses */ +extern uint8_t pci_mem_ld8(uint8_t *adr); +extern void pci_mem_st8(uint8_t *adr, uint8_t data); + +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, +}; diff --git a/cpukit/libpci/pci_access_mem_le.c b/cpukit/libpci/pci_access_mem_le.c new file mode 100644 index 0000000000..d00e13121a --- /dev/null +++ b/cpukit/libpci/pci_access_mem_le.c @@ -0,0 +1,61 @@ +/* Registers-over-Memory Space - Generic Little endian PCI bus definitions */ + +#include <pci.h> + +/* Same for Little and Big endian PCI buses */ +extern uint8_t pci_mem_ld8(uint8_t *adr); +extern void pci_mem_st8(uint8_t *adr, uint8_t data); + +uint16_t pci_mem_le_ld_le16(uint16_t *adr) +{ + return ld_le16(adr); +} + +uint16_t pci_mem_le_ld_be16(uint16_t *adr) +{ + return ld_be16(adr); +} + +uint32_t pci_mem_le_ld_le32(uint32_t *adr) +{ + return ld_le32(adr); +} + +uint32_t pci_mem_le_ld_be32(uint32_t *adr) +{ + return ld_be32(adr); +} + +void pci_mem_le_st_le16(uint16_t *adr, uint16_t data) +{ + st_le16(adr, data); +} + +void pci_mem_le_st_be16(uint16_t *adr, uint16_t data) +{ + st_be16(adr, data); +} + +void pci_mem_le_st_le32(uint32_t *adr, uint32_t data) +{ + st_le32(adr, data); +} + +void pci_mem_le_st_be32(uint32_t *adr, uint32_t data) +{ + st_be32(adr, data); +} + +struct pci_memreg_ops pci_mem_le_ops = { + .ld8 = pci_mem_ld8, + .st8 = pci_mem_st8, + + .ld_le16 = pci_mem_le_ld_le16, + .st_le16 = pci_mem_le_st_le16, + .ld_be16 = pci_mem_le_ld_be16, + .st_be16 = pci_mem_le_st_be16, + .ld_le32 = pci_mem_le_ld_le32, + .st_le32 = pci_mem_le_st_le32, + .ld_be32 = pci_mem_le_ld_be32, + .st_be32 = pci_mem_le_st_be32, +}; diff --git a/cpukit/libpci/pci_bus.c b/cpukit/libpci/pci_bus.c index f3b46f25f2..092789b01b 100644 --- a/cpukit/libpci/pci_bus.c +++ b/cpukit/libpci/pci_bus.c @@ -99,6 +99,16 @@ struct drvmgr_bus_ops pcibus_ops = { #endif }; +struct drvmgr_func pcibus_funcs[] = { + DRVMGR_FUNC(PCI_FUNC_MREG_R8, NULL), + DRVMGR_FUNC(PCI_FUNC_MREG_R16, NULL), + DRVMGR_FUNC(PCI_FUNC_MREG_R32, NULL), + DRVMGR_FUNC(PCI_FUNC_MREG_W8, NULL), + DRVMGR_FUNC(PCI_FUNC_MREG_W16, NULL), + DRVMGR_FUNC(PCI_FUNC_MREG_W32, NULL), + DRVMGR_FUNC_END +}; + /* Driver resources configuration for the PCI bus. It is declared weak so that * the user may override it from the project file, if the default settings are * not enough. @@ -514,6 +524,7 @@ static int pcibus_devs_register(struct drvmgr_bus *bus) int pcibus_register(struct drvmgr_dev *dev) { struct pcibus_priv *priv; + int i, fid, rc; DBG("PCI BUS: initializing\n"); @@ -527,6 +538,16 @@ int pcibus_register(struct drvmgr_dev *dev) dev->bus->dev_cnt = 0; dev->bus->reslist = NULL; dev->bus->mmaps = NULL; + dev->bus->funcs = &pcibus_funcs; + + /* Copy function definitions from PCI Layer */ + for (i=0; i<6; i++) { + fid = pcibus_funcs[i].funcid; + rc = pci_access_func(RW_DIR(fid), RW_SIZE(fid), + &pcibus_funcs[i].func, PCI_LITTLE_ENDIAN, 3); + if (rc != 0) + DBG("PCI BUS: MEMREG 0x%x function not defined\n", fid); + } /* Add resource configuration if user overrided the default empty cfg */ if (pcibus_drv_resources.resource[0].drv_id != 0) diff --git a/cpukit/libpci/pci_bus.h b/cpukit/libpci/pci_bus.h index 9705f28ca1..27d3e921ba 100644 --- a/cpukit/libpci/pci_bus.h +++ b/cpukit/libpci/pci_bus.h @@ -118,59 +118,29 @@ struct pcibus_config { struct pcibus_regmem_ops *memreg_ops; }; -/* Select Sub-Function Read/Write function by ID */ -#define RW_SIZE_1 0x0001 /* Access Size */ -#define RW_SIZE_2 0x0002 -#define RW_SIZE_4 0x0004 -#define RW_SIZE_8 0x0008 -#define RW_SIZE_ANY 0x0000 - -#define RW_DIR_ANY 0x0000 /* Access Direction */ -#define RW_READ 0x0000 -#define RW_WRITE 0x0010 -#define RW_SET 0x0020 - -#define RW_TYPE_ANY 0x0000 /* Access type */ -#define RW_REG 0x0100 -#define RW_MEM 0x0200 -#define RW_MEMREG 0x0300 -#define RW_CFG 0x0400 - -#define RW_ARG 0x1000 /* Optional Argument */ -#define RW_ERR 0x2000 /* Optional Error Handler */ - -/* Build a Read/Write function ID */ -#define DRVMGR_RWFUNC(minor) DRVMGR_FUNCID(FUNCID_RW, minor) - -/* PCI I/O Register Access - Not implemented */ -#define PCI_IO_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_REG) -#define PCI_IO_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_REG) -#define PCI_IO_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_REG) -#define PCI_IO_R64 DRVMGR_RWFUNC(RW_SIZE_8|RW_READ|RW_REG) -#define PCI_IO_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_REG) -#define PCI_IO_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_REG) -#define PCI_IO_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_REG) -#define PCI_IO_W64 DRVMGR_RWFUNC(RW_SIZE_8|RW_WRITE|RW_REG) - -/* PCI Register Access over Memory Space */ -#define PCI_MREG_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_MEMREG) -#define PCI_MREG_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_MEMREG) -#define PCI_MREG_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_MEMREG) -#define PCI_MREG_R64 DRVMGR_RWFUNC(RW_SIZE_8|RW_READ|RW_MEMREG) -#define PCI_MREG_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_MEMREG) -#define PCI_MREG_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_MEMREG) -#define PCI_MREG_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_MEMREG) -#define PCI_MREG_W64 DRVMGR_RWFUNC(RW_SIZE_8|RW_WRITE|RW_MEMREG) - -#if 0 -extern uint8_t pcibus_cfg_r8(struct drvmgr_dev *dev, int ofs); -extern uint16_t pcibus_cfg_r16(struct drvmgr_dev *dev, int ofs); -extern uint32_t pcibus_cfg_r32(struct drvmgr_dev *dev, int ofs); - -extern void pcibus_cfg_w8(struct drvmgr_dev *dev, int ofs, uint8_t value); -extern void pcibus_cfg_w16(struct drvmgr_dev *dev, int ofs, uint16_t value); -extern void pcibus_cfg_w32(struct drvmgr_dev *dev, int ofs, uint32_t value); -#endif +/* PCI Configuration Space Access - Not implemented (use PCI Lib directly) */ +#define PCI_FUNC_CFG_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_CFG) +#define PCI_FUNC_CFG_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_CFG) +#define PCI_FUNC_CFG_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_CFG) +#define PCI_FUNC_CFG_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_CFG) +#define PCI_FUNC_CFG_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_CFG) +#define PCI_FUNC_CFG_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_CFG) + +/* PCI I/O Register Access - Not implemented (use PCI Lib directly) */ +#define PCI_FUNC_IO_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_IO) +#define PCI_FUNC_IO_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_IO) +#define PCI_FUNC_IO_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_IO) +#define PCI_FUNC_IO_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_IO) +#define PCI_FUNC_IO_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_IO) +#define PCI_FUNC_IO_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_IO) + +/* PCI Register Access over Memory Space (Little Endian) */ +#define PCI_FUNC_MREG_R8 DRVMGR_RWFUNC(RW_SIZE_1|RW_READ|RW_MEMREG) +#define PCI_FUNC_MREG_R16 DRVMGR_RWFUNC(RW_SIZE_2|RW_READ|RW_MEMREG|RW_LITTLE) +#define PCI_FUNC_MREG_R32 DRVMGR_RWFUNC(RW_SIZE_4|RW_READ|RW_MEMREG|RW_LITTLE) +#define PCI_FUNC_MREG_W8 DRVMGR_RWFUNC(RW_SIZE_1|RW_WRITE|RW_MEMREG) +#define PCI_FUNC_MREG_W16 DRVMGR_RWFUNC(RW_SIZE_2|RW_WRITE|RW_MEMREG|RW_LITTLE) +#define PCI_FUNC_MREG_W32 DRVMGR_RWFUNC(RW_SIZE_4|RW_WRITE|RW_MEMREG|RW_LITTLE) /* Weak default PCI driver resources, override this from project configuration * to set PCI Bus resources used to configure PCI device drivers. |