Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*  LIBPCI Command Implementation
0004  *
0005  *  COPYRIGHT (c) 2010.
0006  *  Cobham Gaisler AB.
0007  *
0008  * Redistribution and use in source and binary forms, with or without
0009  * modification, are permitted provided that the following conditions
0010  * are met:
0011  * 1. Redistributions of source code must retain the above copyright
0012  *    notice, this list of conditions and the following disclaimer.
0013  * 2. Redistributions in binary form must reproduce the above copyright
0014  *    notice, this list of conditions and the following disclaimer in the
0015  *    documentation and/or other materials provided with the distribution.
0016  *
0017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0027  * POSSIBILITY OF SUCH DAMAGE.
0028  */
0029 
0030 #ifdef HAVE_CONFIG_H
0031 #include "config.h"
0032 #endif
0033 
0034 #include <inttypes.h>
0035 #include <limits.h>
0036 #include <stdlib.h>
0037 #include <stdio.h>
0038 #include <string.h>
0039 #include <errno.h>
0040 #include <pci.h>
0041 #include <pci/cfg.h>
0042 #include <pci/access.h>
0043 #include <sys/endian.h>
0044 
0045 #include <rtems.h>
0046 #include <rtems/shell.h>
0047 #include "internal.h"
0048 
0049 static void usage(void);
0050 
0051 struct shell_pci_modifier {
0052   char *name;
0053   int (*func)(int argc, char *argv[], struct shell_pci_modifier *mod);
0054   int data;
0055 };
0056 
0057 static unsigned long get_pciid_from_string(char *arg)
0058 {
0059   unsigned long pciid;
0060   char *bus_str, *dev_str, *fun_str;
0061   unsigned long busno, devno, funno;
0062 
0063   dev_str = strstr(arg, ":");
0064   if (dev_str == NULL) {
0065     /* PCIID */
0066     pciid = strtoul(arg, NULL, 16);
0067     if (pciid == ULONG_MAX)
0068       return ~0;
0069   } else {
0070     /* bus:dev:fun */
0071     bus_str = arg;
0072     *dev_str = '\0';
0073     dev_str++;
0074     fun_str = strstr(dev_str, ":");
0075     if (fun_str == NULL)
0076       return ~0;
0077     *fun_str = '\0';
0078     fun_str++;
0079 
0080     busno = strtoul(bus_str, NULL, 16);
0081     if (busno == ULONG_MAX)
0082       return ~0;
0083     devno = strtoul(dev_str, NULL, 16);
0084     if (devno == ULONG_MAX)
0085       return ~0;
0086     funno = strtoul(fun_str, NULL, 16);
0087     if (funno == ULONG_MAX)
0088       return ~0;
0089     pciid = PCI_DEV(busno, devno, funno);
0090   }
0091 
0092   return pciid;
0093 }
0094 
0095 /* Print current PCI configuration that can be used in a static/peripheral PCI
0096  * configuration setup.
0097  */
0098 static int shell_pci_pcfg(
0099     int argc,
0100     char *argv[],
0101     struct shell_pci_modifier *mod)
0102 {
0103   if (argc != 2)
0104     return -1;
0105 
0106   pci_cfg_print();
0107 
0108   return 0;
0109 }
0110 
0111 static int shell_pci_ls(
0112     int argc,
0113     char *argv[],
0114     struct shell_pci_modifier *mod)
0115 {
0116   unsigned long pciid;
0117 
0118   if (argc == 2) {
0119     /* List all devices */
0120     pci_print();
0121   } else if (argc > 3) {
0122     return -1;
0123   } else {
0124     pciid = get_pciid_from_string(argv[2]);
0125     if ((pciid & 0xffff0000) != 0)
0126       return -1;
0127 
0128     pci_print_dev((pci_dev_t)pciid);
0129   }
0130   return 0;
0131 }
0132 
0133 static int shell_pci_rX(
0134     unsigned long pciid,
0135     int offset,
0136     int size)
0137 {
0138   uint8_t data8;
0139   uint16_t data16;
0140   uint32_t data32;
0141   int result;
0142 
0143   switch(size) {
0144     case 1:
0145       result = pci_cfg_r8(pciid, offset, &data8);
0146       if (result == PCISTS_OK)
0147         printf(" r08[0x%02x]: 0x%02x  DEC=%d\n", offset, data8, data8);
0148       break;
0149 
0150     case 2:
0151       result = pci_cfg_r16(pciid, offset, &data16);
0152       if (result == PCISTS_OK)
0153         printf(" r16[0x%02x]: 0x%04x  DEC=%d\n", offset, data16, data16);
0154       break;
0155 
0156     case 4:
0157       result = pci_cfg_r32(pciid, offset, &data32);
0158       if (result == PCISTS_OK)
0159         printf(" r32[0x%02x]: 0x%08" PRIx32 "  DEC=%" PRIu32 "\n",
0160                offset, data32, data32);
0161       break;
0162 
0163     default:
0164       return PCISTS_EINVAL;
0165   }
0166   return result;
0167 }
0168 
0169 static int shell_pci_wX(
0170     unsigned long pciid,
0171     int offset,
0172     uint32_t data,
0173     int size)
0174 {
0175   uint8_t data8;
0176   uint16_t data16;
0177   int result;
0178 
0179   switch(size) {
0180     case 1:
0181       if (data > 0xff)
0182         return PCISTS_EINVAL;
0183       data8 = data & 0xff;
0184       result = pci_cfg_w8(pciid, offset, data8);
0185       if (result == PCISTS_OK)
0186         printf(" w08[0x%02x]: 0x%02x  DEC=%d\n", offset, data8, data8);
0187       break;
0188 
0189     case 2:
0190       if (data > 0xffff)
0191         return PCISTS_EINVAL;
0192       data16 = data & 0xffff;
0193       result = pci_cfg_w16(pciid, offset, data16);
0194       if (result == PCISTS_OK)
0195         printf(" w16[0x%02x]: 0x%04x  DEC=%d\n", offset, data16, data16);
0196       break;
0197 
0198     case 4:
0199       result = pci_cfg_w32(pciid, offset, data);
0200       if (result == PCISTS_OK)
0201         printf(" w32[0x%02x]: 0x%08" PRIx32 "  DEC=%" PRIu32 "\n",
0202                offset, data, data);
0203       break;
0204 
0205     default:
0206       return PCISTS_EINVAL;
0207   }
0208   return result;
0209 }
0210 
0211 static int shell_pci_read(
0212     int argc,
0213     char *argv[],
0214     struct shell_pci_modifier *mod)
0215 {
0216   unsigned long pciid, offset;
0217   int result, size;
0218 
0219   if (argc != 4)
0220     return -1;
0221 
0222   pciid = get_pciid_from_string(argv[2]);
0223   if ((pciid & 0xffff0000) != 0)
0224     return -1;
0225 
0226   offset = strtoul(argv[3], NULL, 0);
0227   if (offset > 256)
0228     return -1;
0229 
0230   size = mod->data;
0231   result = shell_pci_rX(pciid, offset, size);
0232   switch (result) {
0233     default:
0234     case PCISTS_OK:
0235       break;
0236 
0237     case PCISTS_ERR:
0238     case PCISTS_EINVAL:
0239       puts(" Bad input argument\n");
0240       return PCISTS_EINVAL;
0241 
0242     case PCISTS_MSTABRT:
0243       puts(" Master abort while reading configuration space");
0244       return PCISTS_MSTABRT;
0245   }
0246 
0247   return 0;
0248 }
0249 
0250 static int shell_pci_write(
0251     int argc,
0252     char *argv[],
0253     struct shell_pci_modifier *mod)
0254 {
0255   unsigned long pciid, offset;
0256   int result, size;
0257   uint32_t data;
0258 
0259   if (argc != 5)
0260     return -1;
0261 
0262   pciid = get_pciid_from_string(argv[2]);
0263   if ((pciid & 0xffff0000) != 0)
0264     return -1;
0265 
0266   offset = strtoul(argv[3], NULL, 0);
0267   if (offset > 256)
0268     return -1;
0269 
0270   data = strtoul(argv[4], NULL, 0);
0271   if (data == ULONG_MAX && errno == ERANGE)
0272     return -1;
0273 
0274   size = mod->data;
0275   result = shell_pci_wX(pciid, offset, data, size);
0276   switch (result) {
0277     default:
0278     case PCISTS_OK:
0279       break;
0280 
0281     case PCISTS_ERR:
0282     case PCISTS_EINVAL:
0283       puts(" Bad input argument\n");
0284       return PCISTS_EINVAL;
0285 
0286     case PCISTS_MSTABRT:
0287       puts(" Master abort while reading configuration space");
0288       return PCISTS_MSTABRT;
0289   }
0290   return 0;
0291 }
0292 
0293 static int shell_pci_pciid(
0294     int argc,
0295     char *argv[],
0296     struct shell_pci_modifier *mod)
0297 {
0298   unsigned long pciid;
0299 
0300   if (argc != 3)
0301     return -1;
0302 
0303   pciid = get_pciid_from_string(argv[2]);
0304   if ((pciid & 0xffff0000) != 0)
0305     return -1;
0306 
0307   printf(" PCIID: 0x%lx [%lx:%lx:%lx]\n", pciid, PCI_DEV_EXPAND(pciid));
0308   return 0;
0309 }
0310 
0311 static int shell_pci_getdev(
0312     int argc,
0313     char *argv[],
0314     struct shell_pci_modifier *mod)
0315 {
0316   unsigned long pciid;
0317   struct pci_dev *dev;
0318 
0319   if (argc != 3)
0320     return -1;
0321 
0322   pciid = get_pciid_from_string(argv[2]);
0323   if ((pciid & 0xffff0000) != 0)
0324     return -1;
0325 
0326   if (pci_get_dev(pciid, &dev)) {
0327     printf(" GETDEV: no device on [%lx:%lx:%lx]\n", PCI_DEV_EXPAND(pciid));
0328     return 0;
0329   }
0330 
0331   printf(" PCI RAM DEVICE: %p\n", dev);
0332   return 0;
0333 }
0334 
0335 static int shell_pci_infodev(
0336     int argc,
0337     char *argv[],
0338     struct shell_pci_modifier *mod)
0339 {
0340   unsigned long arg;
0341   struct pci_dev *dev;
0342   struct pci_bus *bus;
0343   struct pci_res *res;
0344   char *type_str, *str1, *res_types[3] = {" IO16", "MEMIO", "MEM"};
0345   int i, res_avail;
0346 
0347   if (argc != 3)
0348     return -1;
0349 
0350   arg = strtoul(argv[2], NULL, 0);
0351   if (arg == ULONG_MAX && errno == ERANGE)
0352     return -1;
0353 
0354   dev = (struct pci_dev *)arg;
0355   if (!dev) {
0356     printf(" INFODEV: invalid device\n");
0357     return 0;
0358   }
0359 
0360   if (dev->flags & PCI_DEV_BRIDGE) {
0361     type_str = "PCI-to-PCI BRIDGE";
0362     if (!dev->bus)
0363       type_str = "PCI HOST BRIDGE";
0364   } else
0365     type_str = "PCI DEVICE";
0366   printf(" %s at [%x:%x:%x]\n", type_str, PCI_DEV_EXPAND(dev->busdevfun));
0367 
0368   bus = (struct pci_bus *)dev;
0369   if (bus) {
0370     printf(" PRIMARY:       BUS 0x%x\n", bus->pri);
0371     printf(" SECONDARY:     BUS 0x%x\n", bus->num);
0372     printf(" SUB ORDINATE:  BUS 0x%x\n", bus->sord);
0373   }
0374 
0375   printf(" PCIID:         0x%04x\n", dev->busdevfun);
0376   bus = dev->bus;
0377   if (!bus) {
0378     printf(" AT BUS:        via Host Bridge\n");
0379   } else {
0380     printf(" AT BUS:        0x%x via Bridge at [%x:%x:%x]\n", bus->num, 
0381            PCI_DEV_EXPAND(bus->dev.busdevfun));
0382   }
0383   printf(" VENDOR:        0x%04x\n", dev->vendor);
0384   printf(" DEVICE:        0x%04x\n", dev->device);
0385   printf(" SUB VENDOR:    0x%04x\n", dev->subvendor);
0386   printf(" SUB DEVICE:    0x%04x\n", dev->subdevice);
0387   printf(" CLASS:         0x%06" PRIx32 "\n", dev->classrev >> 8);
0388   printf(" REVISION:      0x%02" PRIx32 "\n", dev->classrev & 0xff);
0389   printf(" IRQ:           %d\n", dev->sysirq);
0390 
0391   res_avail = 0;
0392   for (i = 0; i < DEV_RES_CNT; i++) {
0393     res = &dev->resources[i];
0394 
0395     if ((res->flags & PCI_RES_TYPE_MASK) == 0)
0396       continue;
0397 
0398     str1 = res_types[(res->flags & PCI_RES_TYPE_MASK) - 1];
0399     if (res->flags & PCI_RES_IO32)
0400       str1 = " IO32";
0401 
0402     if (res_avail == 0) {
0403       puts(" RESOURCES:");
0404       res_avail = 1;
0405     }
0406 
0407     if (res->flags & PCI_RES_FAIL) {
0408       printf("  %s[%d]:  NOT ASSIGNED", str1, i);
0409       continue;
0410     }
0411 
0412     printf("  %s[%d]:  %08" PRIx32 "-%08" PRIx32 "\n",
0413            str1, i, res->start, res->end - 1);
0414   }
0415 
0416   if (res_avail == 0)
0417     puts(" NO CONFIGURED RESOURCES AVAILABLE");
0418 
0419   return 0;
0420 }
0421 
0422 static int pci_summary(void)
0423 {
0424     char *str;
0425     char *cfglib_strs[5] = {"NONE", "AUTO", "STATIC", "READ", "PERIPHERAL"};
0426 
0427     if (pci_system_type == PCI_SYSTEM_HOST)
0428         str = "HOST";
0429     else if (pci_system_type == PCI_SYSTEM_PERIPHERAL)
0430         str = "PERIPHERAL";
0431     else
0432         str = "UNKNOWN / UNINITIALIZED";
0433     printf(" SYSTEM:            %s\n", str);
0434 
0435     if (pci_config_lib_type > PCI_CONFIG_LIB_PERIPHERAL) {
0436         puts(" Bad configuration library");
0437         return 1;
0438     }
0439     printf(" CFG LIBRARY:       %s\n", cfglib_strs[pci_config_lib_type]);
0440     printf(" NO. PCI BUSES:     %d buses\n", pci_bus_count());
0441     printf(" PCI ENDIAN:        %s\n", pci_endian ? "Big" : "Little");
0442 #if BYTE_ORDER == LITTLE_ENDIAN
0443     puts(" MACHINE ENDIAN:    Little");
0444 #else
0445     puts(" MACHINE ENDIAN:    Big");
0446 #endif
0447 
0448     return 0;
0449 }
0450 
0451 static const char pci_usage_str[] =
0452  " usage:\n"
0453  "  pci ls [bus:dev:fun|PCIID]         List one or all devices\n"
0454  "  pci r{8|16|32} bus:dev:fun OFS     Configuration space read\n"
0455  "  pci r{8|16|32} PCIID OFS           Configuration space read\n"
0456  "                                     access by PCIID\n"
0457  "  pci w{8|16|32} bus:dev:fun OFS D   Configuration space write\n"
0458  "  pci w{8|16|32} PCIID OFS D         Configuration space write\n"
0459  "                                     access by PCIID\n"
0460  "  pci pciid bus:dev:fun              Print PCIID for bus:dev:fun\n"
0461  "  pci pciid PCIID                    Print bus:dev:fun for PCIID\n"
0462  "  pci pcfg                           Print current PCI config for\n"
0463  "                                     static configuration library\n"
0464  "  pci getdev {PCIID|bus:dev:fun}     Get PCI Device from RAM tree\n"
0465  "  pci infodev DEV_ADR                Info about a PCI RAM Device\n"
0466  "  pci --help\n";
0467 
0468 static void usage(void)
0469 {
0470   puts(pci_usage_str);
0471 }
0472 
0473 static int shell_pci_usage(
0474     int argc,
0475     char *argv[],
0476     struct shell_pci_modifier *mod)
0477 {
0478   usage();
0479   return 0;
0480 }
0481 
0482 #define MODIFIER_NUM 12
0483 static struct shell_pci_modifier shell_pci_modifiers[MODIFIER_NUM] =
0484 {
0485   {"ls", shell_pci_ls, 0},
0486   {"r8", shell_pci_read, 1},
0487   {"r16", shell_pci_read, 2},
0488   {"r32", shell_pci_read, 4},
0489   {"w8", shell_pci_write, 1},
0490   {"w16", shell_pci_write, 2},
0491   {"w32", shell_pci_write, 4},
0492   {"pciid", shell_pci_pciid, 0},
0493   {"pcfg", shell_pci_pcfg, 0},
0494   {"getdev", shell_pci_getdev, 0},
0495   {"infodev", shell_pci_infodev, 0},
0496   {"--help", shell_pci_usage},
0497 };
0498 
0499 static struct shell_pci_modifier *shell_pci_find_modifier(char *name)
0500 {
0501   struct shell_pci_modifier *mod;
0502   int i;
0503 
0504   if (name == NULL)
0505     return NULL;
0506 
0507   for (i=0, mod=&shell_pci_modifiers[0]; i<MODIFIER_NUM; i++, mod++) {
0508     if (strcmp(name, mod->name) == 0)
0509       return mod;
0510   }
0511 
0512   return NULL;
0513 }
0514 
0515 static int rtems_shell_main_pci(
0516   int   argc,
0517   char *argv[]
0518 )
0519 {
0520   struct shell_pci_modifier *mod;
0521   int rc;
0522 
0523   if (argc < 2) {
0524     /* without arguments */
0525     pci_summary();
0526     rc = 0;
0527   } else if ((mod=shell_pci_find_modifier(argv[1])) != NULL) {
0528     rc = mod->func(argc, argv, mod);
0529   } else {
0530     rc = -1;
0531   }
0532 
0533   if (rc < 0) {
0534     printf(" invalid argument\n");
0535     usage();
0536   }
0537 
0538   return rc;
0539 }
0540 
0541 rtems_shell_cmd_t rtems_shell_PCI_Command = {
0542   "pci",                         /* name */
0543   pci_usage_str,                 /* usage */
0544   "system",                      /* topic */
0545   rtems_shell_main_pci,          /* command */
0546   NULL,                          /* alias */
0547   NULL                           /* next */
0548 };