summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Hellstrom <daniel@gaisler.com>2011-11-28 10:25:15 +0100
committerDaniel Hellstrom <daniel@gaisler.com>2015-04-17 01:10:15 +0200
commit02550220c57d25d0b718caa77991927e0b0418e5 (patch)
treebe60aaebb949df8173d062ab250b69423f992c56
parentLIBPCI: added PCI layer to cpukit/libpci (diff)
downloadrtems-02550220c57d25d0b718caa77991927e0b0418e5.tar.bz2
LIBPCI: added PCI shell command
-rw-r--r--cpukit/libmisc/Makefile.am3
-rw-r--r--cpukit/libmisc/shell/main_pci.c525
-rw-r--r--cpukit/libmisc/shell/shellconfig.h16
3 files changed, 543 insertions, 1 deletions
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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#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>
+#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]; i<MODIFIER_NUM; i++, mod++) {
+ if (strcmp(name, mod->name) == 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[];
/*
@@ -510,6 +515,17 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[];
#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
*/
#if defined(CONFIGURE_SHELL_USER_COMMANDS)