1/* $NetBSD: pcictl.c,v 1.17 2011/02/25 21:40:48 jmcneill Exp $ */ 2 3/* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/* 39 * pcictl(8) -- a program to manipulate the PCI bus 40 */ 41 42#include <sys/param.h> 43#include <sys/ioctl.h> 44#include <err.h> 45#include <errno.h> 46#include <fcntl.h> 47#include <paths.h> 48#include <pci.h> 49#include <stdio.h> 50#include <stdlib.h> 51#include <string.h> 52#include <unistd.h> 53#include <util.h> 54 55#include <dev/pci/pcireg.h> 56#include <dev/pci/pcidevs.h> 57#include <dev/pci/pciio.h> 58 59struct command { 60 const char *cmd_name; 61 const char *arg_names; 62 void (*cmd_func)(int, char *[]); 63 int open_flags; 64}; 65 66__dead static void usage(void); 67 68static int pcifd; 69 70static struct pciio_businfo pci_businfo; 71 72static const char *dvname; 73static char dvname_store[MAXPATHLEN]; 74static const char *cmdname; 75static int print_numbers = 0; 76 77static void cmd_list(int, char *[]); 78static void cmd_dump(int, char *[]); 79 80static const struct command commands[] = { 81 { "list", 82 "[-n] [-b bus] [-d device] [-f function]", 83 cmd_list, 84 O_RDONLY }, 85 86 { "dump", 87 "[-b bus] -d device [-f function]", 88 cmd_dump, 89 O_RDONLY }, 90 91 { 0, 0, 0, 0 }, 92}; 93 94static int parse_bdf(const char *); 95 96static void scan_pci(int, int, int, void (*)(u_int, u_int, u_int)); 97 98static void scan_pci_list(u_int, u_int, u_int); 99static void scan_pci_dump(u_int, u_int, u_int); 100 101int 102main(int argc, char *argv[]) 103{ 104 int i; 105 106 /* Must have at least: device command */ 107 if (argc < 3) 108 usage(); 109 110 /* Skip program name, get and skip device name, get command. */ 111 dvname = argv[1]; 112 cmdname = argv[2]; 113 argv += 2; 114 argc -= 2; 115 116 /* Look up and call the command. */ 117 for (i = 0; commands[i].cmd_name != NULL; i++) 118 if (strcmp(cmdname, commands[i].cmd_name) == 0) 119 break; 120 if (commands[i].cmd_name == NULL) 121 errx(EXIT_FAILURE, "unknown command: %s", cmdname); 122 123 /* Open the device. */ 124 if ((strchr(dvname, '/') == NULL) && 125 (snprintf(dvname_store, sizeof(dvname_store), _PATH_DEV "%s", 126 dvname) < (int)sizeof(dvname_store))) 127 dvname = dvname_store; 128 pcifd = open(dvname, commands[i].open_flags); 129 if (pcifd < 0) 130 err(EXIT_FAILURE, "%s", dvname); 131 132 /* Make sure the device is a PCI bus. */ 133 if (ioctl(pcifd, PCI_IOC_BUSINFO, &pci_businfo) != 0) 134 errx(EXIT_FAILURE, "%s: not a PCI bus device", dvname); 135 136 (*commands[i].cmd_func)(argc, argv); 137 exit(EXIT_SUCCESS); 138} 139 140static void 141usage(void) 142{ 143 int i; 144 145 fprintf(stderr, "usage: %s device command [arg [...]]\n", 146 getprogname()); 147 148 fprintf(stderr, " Available commands:\n"); 149 for (i = 0; commands[i].cmd_name != NULL; i++) 150 fprintf(stderr, "\t%s %s\n", commands[i].cmd_name, 151 commands[i].arg_names); 152 153 exit(EXIT_FAILURE); 154} 155 156static void 157cmd_list(int argc, char *argv[]) 158{ 159 int bus, dev, func; 160 int ch; 161 162 bus = -1; 163 dev = func = -1; 164 165 while ((ch = getopt(argc, argv, "nb:d:f:")) != -1) { 166 switch (ch) { 167 case 'b': 168 bus = parse_bdf(optarg); 169 break; 170 case 'd': 171 dev = parse_bdf(optarg); 172 break; 173 case 'f': 174 func = parse_bdf(optarg); 175 break; 176 case 'n': 177 print_numbers = 1; 178 break; 179 default: 180 usage(); 181 } 182 } 183 argv += optind; 184 argc -= optind; 185 186 if (argc != 0) 187 usage(); 188 189 scan_pci(bus, dev, func, scan_pci_list); 190} 191 192static void 193cmd_dump(int argc, char *argv[]) 194{ 195 int bus, dev, func; 196 int ch; 197 198 bus = pci_businfo.busno; 199 func = 0; 200 dev = -1; 201 202 while ((ch = getopt(argc, argv, "b:d:f:")) != -1) { 203 switch (ch) { 204 case 'b': 205 bus = parse_bdf(optarg); 206 break; 207 case 'd': 208 dev = parse_bdf(optarg); 209 break; 210 case 'f': 211 func = parse_bdf(optarg); 212 break; 213 default: 214 usage(); 215 } 216 } 217 argv += optind; 218 argc -= optind; 219 220 if (argc != 0) 221 usage(); 222 223 if (bus == -1) 224 errx(EXIT_FAILURE, "dump: wildcard bus number not permitted"); 225 if (dev == -1) 226 errx(EXIT_FAILURE, "dump: must specify a device number"); 227 if (func == -1) 228 errx(EXIT_FAILURE, "dump: wildcard function number not permitted"); 229 230 scan_pci(bus, dev, func, scan_pci_dump); 231} 232 233static int 234parse_bdf(const char *str) 235{ 236 long value; 237 char *end; 238 239 if (strcmp(str, "all") == 0 || 240 strcmp(str, "any") == 0) 241 return (-1); 242 243 value = strtol(str, &end, 0); 244 if (*end != '\0') 245 errx(EXIT_FAILURE, "\"%s\" is not a number", str); 246 247 return value; 248} 249 250static void 251scan_pci(int busarg, int devarg, int funcarg, void (*cb)(u_int, u_int, u_int)) 252{ 253 u_int busmin, busmax; 254 u_int devmin, devmax; 255 u_int funcmin, funcmax; 256 u_int bus, dev, func; 257 pcireg_t id, bhlcr; 258 259 if (busarg == -1) { 260 busmin = 0; 261 busmax = 255; 262 } else 263 busmin = busmax = busarg; 264 265 if (devarg == -1) { 266 devmin = 0; 267 if (pci_businfo.maxdevs <= 0) 268 devmax = 0; 269 else 270 devmax = pci_businfo.maxdevs - 1; 271 } else 272 devmin = devmax = devarg; 273 274 for (bus = busmin; bus <= busmax; bus++) { 275 for (dev = devmin; dev <= devmax; dev++) { 276 if (pcibus_conf_read(pcifd, bus, dev, 0, 277 PCI_BHLC_REG, &bhlcr) != 0) 278 continue; 279 if (funcarg == -1) { 280 funcmin = 0; 281 if (PCI_HDRTYPE_MULTIFN(bhlcr)) 282 funcmax = 7; 283 else 284 funcmax = 0; 285 } else 286 funcmin = funcmax = funcarg; 287 for (func = funcmin; func <= funcmax; func++) { 288 if (pcibus_conf_read(pcifd, bus, dev, 289 func, PCI_ID_REG, &id) != 0) 290 continue; 291 292 /* Invalid vendor ID value? */ 293 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 294 continue; 295 /* 296 * XXX Not invalid, but we've done this 297 * ~forever. 298 */ 299 if (PCI_VENDOR(id) == 0) 300 continue; 301 302 (*cb)(bus, dev, func); 303 } 304 } 305 } 306} 307 308static void 309scan_pci_list(u_int bus, u_int dev, u_int func) 310{ 311 pcireg_t id, class; 312 char devinfo[256]; 313 314 if (pcibus_conf_read(pcifd, bus, dev, func, PCI_ID_REG, &id) != 0) 315 return; 316 if (pcibus_conf_read(pcifd, bus, dev, func, PCI_CLASS_REG, &class) != 0) 317 return; 318 319 printf("%03u:%02u:%01u: ", bus, dev, func); 320 if (print_numbers) { 321 printf("0x%08x (0x%08x)\n", id, class); 322 } else { 323 pci_devinfo(id, class, 1, devinfo, sizeof(devinfo)); 324 printf("%s\n", devinfo); 325 } 326} 327 328static void 329scan_pci_dump(u_int bus, u_int dev, u_int func) 330{ 331 332 pci_conf_print(pcifd, bus, dev, func); 333} 334