1 /* $NetBSD: pcictl.c,v 1.11 2007/02/08 23:27:07 hubertf 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 59 struct command { 60 const char *cmd_name; 61 const char *arg_names; 62 void (*cmd_func)(int, char *[]); 63 int open_flags; 64 }; 65 66 int main(int, char *[]); 67 void usage(void); 68 69 int pcifd; 70 71 struct pciio_businfo pci_businfo; 72 73 const char *dvname; 74 char dvname_store[MAXPATHLEN]; 75 const char *cmdname; 76 const char *argnames; 77 int print_numbers = 0; 78 79 void cmd_list(int, char *[]); 80 void cmd_dump(int, char *[]); 81 82 const struct command commands[] = { 83 { "list", 84 "[-n] [-b bus] [-d device] [-f function]", 85 cmd_list, 86 O_RDONLY }, 87 88 { "dump", 89 "[-b bus] -d device [-f function]", 90 cmd_dump, 91 O_RDONLY }, 92 93 { 0 }, 94 }; 95 96 int parse_bdf(const char *); 97 98 void scan_pci(int, int, int, void (*)(u_int, u_int, u_int)); 99 100 void scan_pci_list(u_int, u_int, u_int); 101 void scan_pci_dump(u_int, u_int, u_int); 102 103 int 104 main(int argc, char *argv[]) 105 { 106 int i; 107 108 /* Must have at least: device command */ 109 if (argc < 3) 110 usage(); 111 112 /* Skip program name, get and skip device name, get command. */ 113 dvname = argv[1]; 114 cmdname = argv[2]; 115 argv += 2; 116 argc -= 2; 117 118 /* Look up and call the command. */ 119 for (i = 0; commands[i].cmd_name != NULL; i++) 120 if (strcmp(cmdname, commands[i].cmd_name) == 0) 121 break; 122 if (commands[i].cmd_name == NULL) 123 errx(1, "unknown command: %s", cmdname); 124 125 argnames = commands[i].arg_names; 126 127 /* Open the device. */ 128 if ((strchr(dvname, '/') == NULL) && 129 (snprintf(dvname_store, sizeof(dvname_store), _PATH_DEV "%s", 130 dvname) < sizeof(dvname_store))) 131 dvname = dvname_store; 132 pcifd = open(dvname, commands[i].open_flags); 133 if (pcifd < 0) 134 err(1, "%s", dvname); 135 136 /* Make sure the device is a PCI bus. */ 137 if (ioctl(pcifd, PCI_IOC_BUSINFO, &pci_businfo) != 0) 138 errx(1, "%s: not a PCI bus device", dvname); 139 140 (*commands[i].cmd_func)(argc, argv); 141 exit(0); 142 } 143 144 void 145 usage() 146 { 147 int i; 148 149 fprintf(stderr, "usage: %s device command [arg [...]]\n", 150 getprogname()); 151 152 fprintf(stderr, " Available commands:\n"); 153 for (i = 0; commands[i].cmd_name != NULL; i++) 154 fprintf(stderr, "\t%s %s\n", commands[i].cmd_name, 155 commands[i].arg_names); 156 157 exit(1); 158 } 159 160 void 161 cmd_list(int argc, char *argv[]) 162 { 163 int bus, dev, func; 164 int ch; 165 166 bus = pci_businfo.busno; 167 dev = func = -1; 168 169 while ((ch = getopt(argc, argv, "nb:d:f:")) != -1) { 170 switch (ch) { 171 case 'b': 172 bus = parse_bdf(optarg); 173 break; 174 case 'd': 175 dev = parse_bdf(optarg); 176 break; 177 case 'f': 178 func = parse_bdf(optarg); 179 break; 180 case 'n': 181 print_numbers = 1; 182 break; 183 default: 184 usage(); 185 } 186 } 187 argv += optind; 188 argc -= optind; 189 190 if (argc != 0) 191 usage(); 192 193 scan_pci(bus, dev, func, scan_pci_list); 194 } 195 196 void 197 cmd_dump(int argc, char *argv[]) 198 { 199 int bus, dev, func; 200 int ch; 201 202 bus = pci_businfo.busno; 203 func = 0; 204 dev = -1; 205 206 while ((ch = getopt(argc, argv, "b:d:f:")) != -1) { 207 switch (ch) { 208 case 'b': 209 bus = parse_bdf(optarg); 210 break; 211 case 'd': 212 dev = parse_bdf(optarg); 213 break; 214 case 'f': 215 func = parse_bdf(optarg); 216 break; 217 default: 218 usage(); 219 } 220 } 221 argv += optind; 222 argc -= optind; 223 224 if (argc != 0) 225 usage(); 226 227 if (bus == -1) 228 errx(1, "dump: wildcard bus number not permitted"); 229 if (dev == -1) 230 errx(1, "dump: must specify a device number"); 231 if (func == -1) 232 errx(1, "dump: wildcard function number not permitted"); 233 234 scan_pci(bus, dev, func, scan_pci_dump); 235 } 236 237 int 238 parse_bdf(const char *str) 239 { 240 long value; 241 char *end; 242 243 if (strcmp(str, "all") == 0 || 244 strcmp(str, "any") == 0) 245 return (-1); 246 247 value = strtol(str, &end, 0); 248 if(*end != '\0') 249 errx(1, "\"%s\" is not a number", str); 250 251 return value; 252 } 253 254 void 255 scan_pci(int busarg, int devarg, int funcarg, void (*cb)(u_int, u_int, u_int)) 256 { 257 u_int busmin, busmax; 258 u_int devmin, devmax; 259 u_int funcmin, funcmax; 260 u_int bus, dev, func; 261 pcireg_t id, bhlcr; 262 263 if (busarg == -1) { 264 busmin = 0; 265 busmax = 255; 266 } else 267 busmin = busmax = busarg; 268 269 if (devarg == -1) { 270 devmin = 0; 271 if (pci_businfo.maxdevs <= 0) 272 devmax = 0; 273 else 274 devmax = pci_businfo.maxdevs - 1; 275 } else 276 devmin = devmax = devarg; 277 278 for (bus = busmin; bus <= busmax; bus++) { 279 for (dev = devmin; dev <= devmax; dev++) { 280 if (pcibus_conf_read(pcifd, bus, dev, 0, 281 PCI_BHLC_REG, &bhlcr) != 0) 282 continue; 283 if (funcarg == -1) { 284 funcmin = 0; 285 if (PCI_HDRTYPE_MULTIFN(bhlcr)) 286 funcmax = 7; 287 else 288 funcmax = 0; 289 } else 290 funcmin = funcmax = funcarg; 291 for (func = funcmin; func <= funcmax; func++) { 292 if (pcibus_conf_read(pcifd, bus, dev, 293 func, PCI_ID_REG, &id) != 0) 294 continue; 295 296 /* Invalid vendor ID value? */ 297 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 298 continue; 299 /* 300 * XXX Not invalid, but we've done this 301 * ~forever. 302 */ 303 if (PCI_VENDOR(id) == 0) 304 continue; 305 306 (*cb)(bus, dev, func); 307 } 308 } 309 } 310 } 311 312 void 313 scan_pci_list(u_int bus, u_int dev, u_int func) 314 { 315 pcireg_t id, class; 316 char devinfo[256]; 317 318 if (pcibus_conf_read(pcifd, bus, dev, func, PCI_ID_REG, &id) != 0) 319 return; 320 if (pcibus_conf_read(pcifd, bus, dev, func, PCI_CLASS_REG, &class) != 0) 321 return; 322 323 printf("%03u:%02u:%01u: ", bus, dev, func); 324 if (print_numbers) { 325 printf("0x%08x (0x%08x)\n", id, class); 326 } else { 327 pci_devinfo(id, class, 1, devinfo, sizeof(devinfo)); 328 printf("%s\n", devinfo); 329 } 330 } 331 332 void 333 scan_pci_dump(u_int bus, u_int dev, u_int func) 334 { 335 336 pci_conf_print(pcifd, bus, dev, func); 337 } 338