source: rtems/cpukit/libmisc/shell/main_pci.c @ 9c12bcfd

5
Last change on this file since 9c12bcfd was 9c12bcfd, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 7, 2019 at 8:32:16 AM

Fix format warnings

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