forked from Imagelibrary/rtems
LIBPCI: added PCI shell command
This commit is contained in:
@@ -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
|
||||
|
||||
525
cpukit/libmisc/shell/main_pci.c
Normal file
525
cpukit/libmisc/shell/main_pci.c
Normal file
@@ -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 */
|
||||
};
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user