From 02550220c57d25d0b718caa77991927e0b0418e5 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Mon, 28 Nov 2011 10:25:15 +0100 Subject: LIBPCI: added PCI shell command --- cpukit/libmisc/Makefile.am | 3 +- cpukit/libmisc/shell/main_pci.c | 525 +++++++++++++++++++++++++++++++++++++ cpukit/libmisc/shell/shellconfig.h | 16 ++ 3 files changed, 543 insertions(+), 1 deletion(-) create mode 100644 cpukit/libmisc/shell/main_pci.c diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am index ac703adc93..47db7e96ad 100644 --- a/cpukit/libmisc/Makefile.am +++ b/cpukit/libmisc/Makefile.am @@ -110,7 +110,8 @@ libshell_a_SOURCES = shell/cat_file.c shell/cmds.c shell/internal.h \ shell/main_mkrfs.c shell/main_debugrfs.c shell/main_df.c \ shell/main_lsof.c shell/main_edit.c \ shell/main_blkstats.c shell/main_rtrace.c \ - shell/shell-wait-for-input.c + shell/shell-wait-for-input.c \ + shell/main_pci.c libshell_a_SOURCES += shell/main_cmdls.c libshell_a_SOURCES += shell/main_cmdchown.c libshell_a_SOURCES += shell/main_cmdchmod.c diff --git a/cpukit/libmisc/shell/main_pci.c b/cpukit/libmisc/shell/main_pci.c new file mode 100644 index 0000000000..c1d9535459 --- /dev/null +++ b/cpukit/libmisc/shell/main_pci.c @@ -0,0 +1,525 @@ +/* LIBPCI Command Implementation + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For PCI endianness config */ + +#include +#include +#include "internal.h" + +static void usage(void); + +struct shell_pci_modifier { + char *name; + int (*func)(int argc, char *argv[], struct shell_pci_modifier *mod); + int data; +}; + +static unsigned long get_pciid_from_string(char *arg) +{ + unsigned long pciid; + char *bus_str, *dev_str, *fun_str; + unsigned long busno, devno, funno; + + dev_str = strstr(arg, ":"); + if (dev_str == NULL) { + /* PCIID */ + pciid = strtoul(arg, NULL, 16); + if (pciid == ULONG_MAX) + return ~0; + } else { + /* bus:dev:fun */ + bus_str = arg; + *dev_str = '\0'; + dev_str++; + fun_str = strstr(dev_str, ":"); + if (fun_str == NULL) + return ~0; + *fun_str = '\0'; + fun_str++; + + busno = strtoul(bus_str, NULL, 16); + if (busno == ULONG_MAX) + return ~0; + devno = strtoul(dev_str, NULL, 16); + if (devno == ULONG_MAX) + return ~0; + funno = strtoul(fun_str, NULL, 16); + if (funno == ULONG_MAX) + return ~0; + pciid = PCI_DEV(busno, devno, funno); + } + + return pciid; +} + +/* Print current PCI configuration that can be used in a static/peripheral PCI + * configuration setup. + */ +static int shell_pci_pcfg( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + if (argc != 2) + return -1; + + pci_cfg_print(); + + return 0; +} + +static int shell_pci_ls( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + unsigned long pciid; + + if (argc == 2) { + /* List all devices */ + pci_print(); + } else if (argc > 3) { + return -1; + } else { + pciid = get_pciid_from_string(argv[2]); + if ((pciid & 0xffff0000) != 0) + return -1; + + pci_print_dev((pci_dev_t)pciid); + } + return 0; +} + +static int shell_pci_rX( + unsigned long pciid, + int offset, + int size) +{ + uint8_t data8; + uint16_t data16; + uint32_t data32; + int result; + + switch(size) { + case 1: + result = pci_cfg_r8(pciid, offset, &data8); + if (result == PCISTS_OK) + printf(" r08[0x%02x]: 0x%02x DEC=%d\n", offset, data8, data8); + break; + + case 2: + result = pci_cfg_r16(pciid, offset, &data16); + if (result == PCISTS_OK) + printf(" r16[0x%02x]: 0x%04x DEC=%d\n", offset, data16, data16); + break; + + case 4: + result = pci_cfg_r32(pciid, offset, &data32); + if (result == PCISTS_OK) + printf(" r32[0x%02x]: 0x%08lx DEC=%lu\n", offset, data32, data32); + break; + + default: + return PCISTS_EINVAL; + } + return result; +} + +static int shell_pci_wX( + unsigned long pciid, + int offset, + uint32_t data, + int size) +{ + uint8_t data8; + uint16_t data16; + int result; + + switch(size) { + case 1: + if (data > 0xff) + return PCISTS_EINVAL; + data8 = data & 0xff; + result = pci_cfg_w8(pciid, offset, data8); + if (result == PCISTS_OK) + printf(" w08[0x%02x]: 0x%02x DEC=%d\n", offset, data8, data8); + break; + + case 2: + if (data > 0xffff) + return PCISTS_EINVAL; + data16 = data & 0xffff; + result = pci_cfg_w16(pciid, offset, data16); + if (result == PCISTS_OK) + printf(" w16[0x%02x]: 0x%04x DEC=%d\n", offset, data16, data16); + break; + + case 4: + result = pci_cfg_w32(pciid, offset, data); + if (result == PCISTS_OK) + printf(" w32[0x%02x]: 0x%08lx DEC=%lu\n", offset, data, data); + break; + + default: + return PCISTS_EINVAL; + } + return result; +} + +static int shell_pci_read( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + unsigned long pciid, offset; + int result, size; + + if (argc != 4) + return -1; + + pciid = get_pciid_from_string(argv[2]); + if ((pciid & 0xffff0000) != 0) + return -1; + + offset = strtoul(argv[3], NULL, 0); + if (offset > 256) + return -1; + + size = mod->data; + result = shell_pci_rX(pciid, offset, size); + switch (result) { + default: + case PCISTS_OK: + break; + + case PCISTS_ERR: + case PCISTS_EINVAL: + puts(" Bad input argument\n"); + return PCISTS_EINVAL; + + case PCISTS_MSTABRT: + puts(" Master abort while reading configuration space"); + return PCISTS_MSTABRT; + } + + return 0; +} + +static int shell_pci_write( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + unsigned long pciid, offset; + int result, size; + uint32_t data; + + if (argc != 5) + return -1; + + pciid = get_pciid_from_string(argv[2]); + if ((pciid & 0xffff0000) != 0) + return -1; + + offset = strtoul(argv[3], NULL, 0); + if (offset > 256) + return -1; + + data = strtoul(argv[4], NULL, 0); + if (data == ULONG_MAX && errno == ERANGE) + return -1; + + size = mod->data; + result = shell_pci_wX(pciid, offset, data, size); + switch (result) { + default: + case PCISTS_OK: + break; + + case PCISTS_ERR: + case PCISTS_EINVAL: + puts(" Bad input argument\n"); + return PCISTS_EINVAL; + + case PCISTS_MSTABRT: + puts(" Master abort while reading configuration space"); + return PCISTS_MSTABRT; + } + return 0; +} + +static int shell_pci_pciid( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + unsigned long pciid; + + if (argc != 3) + return -1; + + pciid = get_pciid_from_string(argv[2]); + if ((pciid & 0xffff0000) != 0) + return -1; + + printf(" PCIID: 0x%lx [%lx:%lx:%lx]\n", pciid, PCI_DEV_EXPAND(pciid)); + return 0; +} + +static int shell_pci_getdev( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + unsigned long pciid; + struct pci_dev *dev; + + if (argc != 3) + return -1; + + pciid = get_pciid_from_string(argv[2]); + if ((pciid & 0xffff0000) != 0) + return -1; + + if (pci_get_dev(pciid, &dev)) { + printf(" GETDEV: no device on [%lx:%lx:%lx]\n", PCI_DEV_EXPAND(pciid)); + return 0; + } + + printf(" PCI RAM DEVICE: %p\n", dev); + return 0; +} + +static int shell_pci_infodev( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + unsigned long arg; + struct pci_dev *dev; + struct pci_bus *bus; + struct pci_res *res; + char *type_str, *str1, *res_types[3] = {" IO16", "MEMIO", "MEM"}; + int i, res_avail; + + if (argc != 3) + return -1; + + arg = strtoul(argv[2], NULL, 0); + if (arg == ULONG_MAX && errno == ERANGE) + return -1; + + dev = (struct pci_dev *)arg; + if (!dev) { + printf(" INFODEV: invalid device\n"); + return 0; + } + + if (dev->flags & PCI_DEV_BRIDGE) { + type_str = "PCI-to-PCI BRIDGE"; + if (!dev->bus) + type_str = "PCI HOST BRIDGE"; + } else + type_str = "PCI DEVICE"; + printf(" %s at [%x:%x:%x]\n", type_str, PCI_DEV_EXPAND(dev->busdevfun)); + + bus = (struct pci_bus *)dev; + if (bus) { + printf(" PRIMARY: BUS 0x%x\n", bus->pri); + printf(" SECONDARY: BUS 0x%x\n", bus->num); + printf(" SUB ORDINATE: BUS 0x%x\n", bus->sord); + } + + printf(" PCIID: 0x%04x\n", dev->busdevfun); + bus = dev->bus; + if (!bus) { + printf(" AT BUS: 0x%x via Host Bridge\n", bus->num); + } else { + printf(" AT BUS: 0x%x via Bridge at [%x:%x:%x]\n", bus->num, + PCI_DEV_EXPAND(bus->dev.busdevfun)); + } + printf(" VENDOR: 0x%04x\n", dev->vendor); + printf(" DEVICE: 0x%04x\n", dev->device); + printf(" SUB VENDOR: 0x%04x\n", dev->subvendor); + printf(" SUB DEVICE: 0x%04x\n", dev->subdevice); + printf(" CLASS: 0x%06lx\n", dev->classrev >> 8); + printf(" REVISION: 0x%02lx\n", dev->classrev & 0xff); + printf(" IRQ: %d\n", dev->sysirq); + + res_avail = 0; + for (i = 0; i < DEV_RES_CNT; i++) { + res = &dev->resources[i]; + + if ((res->flags & PCI_RES_TYPE_MASK) == 0) + continue; + + str1 = res_types[(res->flags & PCI_RES_TYPE_MASK) - 1]; + if (res->flags & PCI_RES_IO32) + str1 = " IO32"; + + if (res_avail == 0) { + puts(" RESOURCES:"); + res_avail = 1; + } + + if (res->flags & PCI_RES_FAIL) { + printf(" %s[%d]: NOT ASSIGNED", str1, i); + continue; + } + + printf(" %s[%d]: %08lx-%08lx\n", str1, i, res->start, res->end - 1); + } + + if (res_avail == 0) + puts(" NO CONFIGURED RESOURCES AVAILABLE"); + + return 0; +} + +static 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; +} + +static const char pci_usage_str[] = + " usage:\n" + " pci ls [bus:dev:fun|PCIID] List one or all devices\n" + " pci r{8|16|32} bus:dev:fun OFS Configuration space read\n" + " pci r{8|16|32} PCIID OFS Configuration space read\n" + " access by PCIID\n" + " pci w{8|16|32} bus:dev:fun OFS D Configuration space write\n" + " pci w{8|16|32} PCIID OFS D Configuration space write\n" + " access by PCIID\n" + " pci pciid bus:dev:fun Print PCIID for bus:dev:fun\n" + " pci pciid PCIID Print bus:dev:fun for PCIID\n" + " pci pcfg Print current PCI config for\n" + " static configuration library\n" + " pci getdev {PCIID|bus:dev:fun} Get PCI Device from RAM tree\n" + " pci infodev DEV_ADR Info about a PCI RAM Device\n" + " pci --help\n"; + +static void usage(void) +{ + puts(pci_usage_str); +} + +static int shell_pci_usage( + int argc, + char *argv[], + struct shell_pci_modifier *mod) +{ + usage(); + return 0; +} + +#define MODIFIER_NUM 12 +static struct shell_pci_modifier shell_pci_modifiers[MODIFIER_NUM] = +{ + {"ls", shell_pci_ls, 0}, + {"r8", shell_pci_read, 1}, + {"r16", shell_pci_read, 2}, + {"r32", shell_pci_read, 4}, + {"w8", shell_pci_write, 1}, + {"w16", shell_pci_write, 2}, + {"w32", shell_pci_write, 4}, + {"pciid", shell_pci_pciid, 0}, + {"pcfg", shell_pci_pcfg, 0}, + {"getdev", shell_pci_getdev, 0}, + {"infodev", shell_pci_infodev, 0}, + {"--help", shell_pci_usage}, +}; + +static struct shell_pci_modifier *shell_pci_find_modifier(char *name) +{ + struct shell_pci_modifier *mod; + int i; + + if (name == NULL) + return NULL; + + for (i=0, mod=&shell_pci_modifiers[0]; iname) == 0) + return mod; + } + + return NULL; +} + +static int rtems_shell_main_pci( + int argc, + char *argv[] +) +{ + struct shell_pci_modifier *mod; + int rc; + + if (argc < 2) { + /* without arguments */ + pci_summary(); + rc = 0; + } else if ((mod=shell_pci_find_modifier(argv[1])) != NULL) { + rc = mod->func(argc, argv, mod); + } else { + rc = -1; + } + + if (rc < 0) { + printf(" invalid argument\n"); + usage(); + } + + return rc; +} + +rtems_shell_cmd_t rtems_shell_PCI_Command = { + "pci", /* name */ + pci_usage_str, /* usage */ + "system", /* topic */ + rtems_shell_main_pci, /* command */ + NULL, /* alias */ + NULL /* next */ +}; diff --git a/cpukit/libmisc/shell/shellconfig.h b/cpukit/libmisc/shell/shellconfig.h index 9023a60274..c1f361b7be 100644 --- a/cpukit/libmisc/shell/shellconfig.h +++ b/cpukit/libmisc/shell/shellconfig.h @@ -95,6 +95,11 @@ extern rtems_shell_cmd_t rtems_shell_RTRACE_Command; extern rtems_shell_cmd_t rtems_shell_PING_Command; #endif +/* + * Extern for System commands + */ +extern rtems_shell_cmd_t rtems_shell_PCI_Command; + extern rtems_shell_cmd_t * const rtems_shell_Initial_commands[]; /* @@ -509,6 +514,17 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[]; &rtems_shell_RTC_Command, #endif + /* + * System related commands + */ + #if defined(RTEMS_PCI_CONFIG_LIB) + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) && \ + !defined(CONFIGURE_SHELL_NO_COMMAND_PCI)) || \ + defined(CONFIGURE_SHELL_COMMAND_PCI) + &rtems_shell_PCI_Command, + #endif + #endif + /* * User defined shell commands */ -- cgit v1.2.3