source: rtems/cpukit/libmisc/shell/main_pci.c @ 4e100058

5
Last change on this file since 4e100058 was 4e100058, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 2, 2018 at 2:34:40 PM

sparc: Remove <bsp.h> from PCI shell command

Update #3254.
Update #3260.

  • Property mode set to 100644
File size: 11.5 KB
Line 
1/*  LIBPCI Command Implementation
2 *
3 *  COPYRIGHT (c) 2010.
4 *  Cobham Gaisler AB.
5 *
6 *  The license and distribution terms for this file may be
7 *  found in the file LICENSE in this distribution or at
8 *  http://www.rtems.com/license/LICENSE.
9 */
10
11#ifdef HAVE_CONFIG_H
12#include "config.h"
13#endif
14
15#include <limits.h>
16#include <stdlib.h>
17#include <stdio.h>
18#include <string.h>
19#include <errno.h>
20#include <pci.h>
21#include <pci/cfg.h>
22#include <pci/access.h>
23#include <sys/endian.h>
24
25#include <rtems.h>
26#include <rtems/shell.h>
27#include "internal.h"
28
29static void usage(void);
30
31struct shell_pci_modifier {
32  char *name;
33  int (*func)(int argc, char *argv[], struct shell_pci_modifier *mod);
34  int data;
35};
36
37static unsigned long get_pciid_from_string(char *arg)
38{
39  unsigned long pciid;
40  char *bus_str, *dev_str, *fun_str;
41  unsigned long busno, devno, funno;
42
43  dev_str = strstr(arg, ":");
44  if (dev_str == NULL) {
45    /* PCIID */
46    pciid = strtoul(arg, NULL, 16);
47    if (pciid == ULONG_MAX)
48      return ~0;
49  } else {
50    /* bus:dev:fun */
51    bus_str = arg;
52    *dev_str = '\0';
53    dev_str++;
54    fun_str = strstr(dev_str, ":");
55    if (fun_str == NULL)
56      return ~0;
57    *fun_str = '\0';
58    fun_str++;
59
60    busno = strtoul(bus_str, NULL, 16);
61    if (busno == ULONG_MAX)
62      return ~0;
63    devno = strtoul(dev_str, NULL, 16);
64    if (devno == ULONG_MAX)
65      return ~0;
66    funno = strtoul(fun_str, NULL, 16);
67    if (funno == ULONG_MAX)
68      return ~0;
69    pciid = PCI_DEV(busno, devno, funno);
70  }
71
72  return pciid;
73}
74
75/* Print current PCI configuration that can be used in a static/peripheral PCI
76 * configuration setup.
77 */
78static int shell_pci_pcfg(
79        int argc,
80        char *argv[],
81        struct shell_pci_modifier *mod)
82{
83  if (argc != 2)
84    return -1;
85
86  pci_cfg_print();
87
88  return 0;
89}
90
91static int shell_pci_ls(
92        int argc,
93        char *argv[],
94        struct shell_pci_modifier *mod)
95{
96  unsigned long pciid;
97
98  if (argc == 2) {
99    /* List all devices */
100    pci_print();
101  } else if (argc > 3) {
102    return -1;
103  } else {
104    pciid = get_pciid_from_string(argv[2]);
105    if ((pciid & 0xffff0000) != 0)
106      return -1;
107
108    pci_print_dev((pci_dev_t)pciid);
109  }
110  return 0;
111}
112
113static int shell_pci_rX(
114        unsigned long pciid,
115        int offset,
116        int size)
117{
118  uint8_t data8;
119  uint16_t data16;
120  uint32_t data32;
121  int result;
122
123  switch(size) {
124    case 1:
125      result = pci_cfg_r8(pciid, offset, &data8);
126      if (result == PCISTS_OK)
127        printf(" r08[0x%02x]: 0x%02x  DEC=%d\n", offset, data8, data8);
128      break;
129
130    case 2:
131      result = pci_cfg_r16(pciid, offset, &data16);
132      if (result == PCISTS_OK)
133        printf(" r16[0x%02x]: 0x%04x  DEC=%d\n", offset, data16, data16);
134      break;
135
136    case 4:
137      result = pci_cfg_r32(pciid, offset, &data32);
138      if (result == PCISTS_OK)
139        printf(" r32[0x%02x]: 0x%08lx  DEC=%lu\n", offset, data32, data32);
140      break;
141
142    default:
143      return PCISTS_EINVAL;
144  }
145  return result;
146}
147
148static int shell_pci_wX(
149        unsigned long pciid,
150        int offset,
151        uint32_t data,
152        int size)
153{
154  uint8_t data8;
155  uint16_t data16;
156  int result;
157
158  switch(size) {
159    case 1:
160      if (data > 0xff)
161        return PCISTS_EINVAL;
162      data8 = data & 0xff;
163      result = pci_cfg_w8(pciid, offset, data8);
164      if (result == PCISTS_OK)
165        printf(" w08[0x%02x]: 0x%02x  DEC=%d\n", offset, data8, data8);
166      break;
167
168    case 2:
169      if (data > 0xffff)
170        return PCISTS_EINVAL;
171      data16 = data & 0xffff;
172      result = pci_cfg_w16(pciid, offset, data16);
173      if (result == PCISTS_OK)
174        printf(" w16[0x%02x]: 0x%04x  DEC=%d\n", offset, data16, data16);
175      break;
176
177    case 4:
178      result = pci_cfg_w32(pciid, offset, data);
179      if (result == PCISTS_OK)
180        printf(" w32[0x%02x]: 0x%08lx  DEC=%lu\n", offset, data, data);
181      break;
182
183    default:
184      return PCISTS_EINVAL;
185  }
186  return result;
187}
188
189static int shell_pci_read(
190        int argc,
191        char *argv[],
192        struct shell_pci_modifier *mod)
193{
194  unsigned long pciid, offset;
195  int result, size;
196
197  if (argc != 4)
198    return -1;
199
200  pciid = get_pciid_from_string(argv[2]);
201  if ((pciid & 0xffff0000) != 0)
202    return -1;
203
204  offset = strtoul(argv[3], NULL, 0);
205  if (offset > 256)
206    return -1;
207
208  size = mod->data;
209  result = shell_pci_rX(pciid, offset, size);
210  switch (result) {
211    default:
212    case PCISTS_OK:
213      break;
214
215    case PCISTS_ERR:
216    case PCISTS_EINVAL:
217      puts(" Bad input argument\n");
218      return PCISTS_EINVAL;
219
220    case PCISTS_MSTABRT:
221      puts(" Master abort while reading configuration space");
222      return PCISTS_MSTABRT;
223  }
224
225  return 0;
226}
227
228static int shell_pci_write(
229        int argc,
230        char *argv[],
231        struct shell_pci_modifier *mod)
232{
233  unsigned long pciid, offset;
234  int result, size;
235  uint32_t data;
236
237  if (argc != 5)
238    return -1;
239
240  pciid = get_pciid_from_string(argv[2]);
241  if ((pciid & 0xffff0000) != 0)
242    return -1;
243
244  offset = strtoul(argv[3], NULL, 0);
245  if (offset > 256)
246    return -1;
247
248  data = strtoul(argv[4], NULL, 0);
249  if (data == ULONG_MAX && errno == ERANGE)
250    return -1;
251
252  size = mod->data;
253  result = shell_pci_wX(pciid, offset, data, size);
254  switch (result) {
255    default:
256    case PCISTS_OK:
257      break;
258
259    case PCISTS_ERR:
260    case PCISTS_EINVAL:
261      puts(" Bad input argument\n");
262      return PCISTS_EINVAL;
263
264    case PCISTS_MSTABRT:
265      puts(" Master abort while reading configuration space");
266      return PCISTS_MSTABRT;
267  }
268  return 0;
269}
270
271static int shell_pci_pciid(
272        int argc,
273        char *argv[],
274        struct shell_pci_modifier *mod)
275{
276  unsigned long pciid;
277
278  if (argc != 3)
279    return -1;
280
281  pciid = get_pciid_from_string(argv[2]);
282  if ((pciid & 0xffff0000) != 0)
283    return -1;
284
285  printf(" PCIID: 0x%lx [%lx:%lx:%lx]\n", pciid, PCI_DEV_EXPAND(pciid));
286  return 0;
287}
288
289static int shell_pci_getdev(
290        int argc,
291        char *argv[],
292        struct shell_pci_modifier *mod)
293{
294  unsigned long pciid;
295  struct pci_dev *dev;
296
297  if (argc != 3)
298    return -1;
299
300  pciid = get_pciid_from_string(argv[2]);
301  if ((pciid & 0xffff0000) != 0)
302    return -1;
303
304  if (pci_get_dev(pciid, &dev)) {
305    printf(" GETDEV: no device on [%lx:%lx:%lx]\n", PCI_DEV_EXPAND(pciid));
306    return 0;
307  }
308
309  printf(" PCI RAM DEVICE: %p\n", dev);
310  return 0;
311}
312
313static int shell_pci_infodev(
314        int argc,
315        char *argv[],
316        struct shell_pci_modifier *mod)
317{
318  unsigned long arg;
319  struct pci_dev *dev;
320  struct pci_bus *bus;
321  struct pci_res *res;
322  char *type_str, *str1, *res_types[3] = {" IO16", "MEMIO", "MEM"};
323  int i, res_avail;
324
325  if (argc != 3)
326    return -1;
327
328  arg = strtoul(argv[2], NULL, 0);
329  if (arg == ULONG_MAX && errno == ERANGE)
330    return -1;
331
332  dev = (struct pci_dev *)arg;
333  if (!dev) {
334    printf(" INFODEV: invalid device\n");
335    return 0;
336  }
337
338  if (dev->flags & PCI_DEV_BRIDGE) {
339    type_str = "PCI-to-PCI BRIDGE";
340    if (!dev->bus)
341      type_str = "PCI HOST BRIDGE";
342  } else
343    type_str = "PCI DEVICE";
344  printf(" %s at [%x:%x:%x]\n", type_str, PCI_DEV_EXPAND(dev->busdevfun));
345
346  bus = (struct pci_bus *)dev;
347  if (bus) {
348    printf(" PRIMARY:       BUS 0x%x\n", bus->pri);
349    printf(" SECONDARY:     BUS 0x%x\n", bus->num);
350    printf(" SUB ORDINATE:  BUS 0x%x\n", bus->sord);
351  }
352
353  printf(" PCIID:         0x%04x\n", dev->busdevfun);
354  bus = dev->bus;
355  if (!bus) {
356    printf(" AT BUS:        0x%x via Host Bridge\n", bus->num);
357  } else {
358    printf(" AT BUS:        0x%x via Bridge at [%x:%x:%x]\n", bus->num, 
359           PCI_DEV_EXPAND(bus->dev.busdevfun));
360  }
361  printf(" VENDOR:        0x%04x\n", dev->vendor);
362  printf(" DEVICE:        0x%04x\n", dev->device);
363  printf(" SUB VENDOR:    0x%04x\n", dev->subvendor);
364  printf(" SUB DEVICE:    0x%04x\n", dev->subdevice);
365  printf(" CLASS:         0x%06lx\n", dev->classrev >> 8);
366  printf(" REVISION:      0x%02lx\n", dev->classrev & 0xff);
367  printf(" IRQ:           %d\n", dev->sysirq);
368
369  res_avail = 0;
370  for (i = 0; i < DEV_RES_CNT; i++) {
371    res = &dev->resources[i];
372
373    if ((res->flags & PCI_RES_TYPE_MASK) == 0)
374      continue;
375
376    str1 = res_types[(res->flags & PCI_RES_TYPE_MASK) - 1];
377    if (res->flags & PCI_RES_IO32)
378      str1 = " IO32";
379
380    if (res_avail == 0) {
381      puts(" RESOURCES:");
382      res_avail = 1;
383    }
384
385    if (res->flags & PCI_RES_FAIL) {
386      printf("  %s[%d]:  NOT ASSIGNED", str1, i);
387      continue;
388    }
389
390    printf("  %s[%d]:  %08lx-%08lx\n", str1, i, res->start, res->end - 1);
391  }
392
393  if (res_avail == 0)
394    puts(" NO CONFIGURED RESOURCES AVAILABLE");
395
396  return 0;
397}
398
399static int pci_summary(void)
400{
401        char *str;
402        char *cfglib_strs[5] = {"NONE", "AUTO", "STATIC", "READ", "PERIPHERAL"};
403
404        if (pci_system_type == PCI_SYSTEM_HOST)
405                str = "HOST";
406        else if (pci_system_type == PCI_SYSTEM_PERIPHERAL)
407                str = "PERIPHERAL";
408        else
409                str = "UNKNOWN / UNINITIALIZED";
410        printf(" SYSTEM:            %s\n", str);
411
412        if (pci_config_lib_type > PCI_CONFIG_LIB_PERIPHERAL) {
413                puts(" Bad configuration library");
414                return 1;
415        }
416        printf(" CFG LIBRARY:       %s\n", cfglib_strs[pci_config_lib_type]);
417        printf(" NO. PCI BUSES:     %d buses\n", pci_bus_count());
418        printf(" PCI ENDIAN:        %s\n", pci_endian ? "Big" : "Little");
419#if BYTE_ORDER == LITTLE_ENDIAN
420        puts(" MACHINE ENDIAN:    Little");
421#else
422        puts(" MACHINE ENDIAN:    Big");
423#endif
424
425        return 0;
426}
427
428static const char pci_usage_str[] =
429 " usage:\n"
430 "  pci ls [bus:dev:fun|PCIID]         List one or all devices\n"
431 "  pci r{8|16|32} bus:dev:fun OFS     Configuration space read\n"
432 "  pci r{8|16|32} PCIID OFS           Configuration space read\n"
433 "                                     access by PCIID\n"
434 "  pci w{8|16|32} bus:dev:fun OFS D   Configuration space write\n"
435 "  pci w{8|16|32} PCIID OFS D         Configuration space write\n"
436 "                                     access by PCIID\n"
437 "  pci pciid bus:dev:fun              Print PCIID for bus:dev:fun\n"
438 "  pci pciid PCIID                    Print bus:dev:fun for PCIID\n"
439 "  pci pcfg                           Print current PCI config for\n"
440 "                                     static configuration library\n"
441 "  pci getdev {PCIID|bus:dev:fun}     Get PCI Device from RAM tree\n"
442 "  pci infodev DEV_ADR                Info about a PCI RAM Device\n"
443 "  pci --help\n";
444
445static void usage(void)
446{
447  puts(pci_usage_str);
448}
449
450static int shell_pci_usage(
451        int argc,
452        char *argv[],
453        struct shell_pci_modifier *mod)
454{
455  usage();
456  return 0;
457}
458
459#define MODIFIER_NUM 12
460static struct shell_pci_modifier shell_pci_modifiers[MODIFIER_NUM] =
461{
462  {"ls", shell_pci_ls, 0},
463  {"r8", shell_pci_read, 1},
464  {"r16", shell_pci_read, 2},
465  {"r32", shell_pci_read, 4},
466  {"w8", shell_pci_write, 1},
467  {"w16", shell_pci_write, 2},
468  {"w32", shell_pci_write, 4},
469  {"pciid", shell_pci_pciid, 0},
470  {"pcfg", shell_pci_pcfg, 0},
471  {"getdev", shell_pci_getdev, 0},
472  {"infodev", shell_pci_infodev, 0},
473  {"--help", shell_pci_usage},
474};
475
476static struct shell_pci_modifier *shell_pci_find_modifier(char *name)
477{
478  struct shell_pci_modifier *mod;
479  int i;
480
481  if (name == NULL)
482    return NULL;
483
484  for (i=0, mod=&shell_pci_modifiers[0]; i<MODIFIER_NUM; i++, mod++) {
485    if (strcmp(name, mod->name) == 0)
486      return mod;
487  }
488
489  return NULL;
490}
491
492static int rtems_shell_main_pci(
493  int   argc,
494  char *argv[]
495)
496{
497  struct shell_pci_modifier *mod;
498  int rc;
499
500  if (argc < 2) {
501    /* without arguments */
502    pci_summary();
503    rc = 0;
504  } else if ((mod=shell_pci_find_modifier(argv[1])) != NULL) {
505    rc = mod->func(argc, argv, mod);
506  } else {
507    rc = -1;
508  }
509
510  if (rc < 0) {
511    printf(" invalid argument\n");
512    usage();
513  }
514
515  return rc;
516}
517
518rtems_shell_cmd_t rtems_shell_PCI_Command = {
519  "pci",                         /* name */
520  pci_usage_str,                 /* usage */
521  "system",                      /* topic */
522  rtems_shell_main_pci,          /* command */
523  NULL,                          /* alias */
524  NULL                           /* next */
525};
Note: See TracBrowser for help on using the repository browser.