| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: pcictl.c,v 1.18 2011/08/30 20:08:38 joerg Exp $ */ | | 1 | /* $NetBSD: pcictl.c,v 1.18.20.1 2014/09/10 08:38:31 martin Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright 2001 Wasabi Systems, Inc. | | 4 | * Copyright 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -66,42 +66,55 @@ struct command { | | | @@ -66,42 +66,55 @@ struct command { |
66 | __dead static void usage(void); | | 66 | __dead static void usage(void); |
67 | | | 67 | |
68 | static int pcifd; | | 68 | static int pcifd; |
69 | | | 69 | |
70 | static struct pciio_businfo pci_businfo; | | 70 | static struct pciio_businfo pci_businfo; |
71 | | | 71 | |
72 | static const char *dvname; | | 72 | static const char *dvname; |
73 | static char dvname_store[MAXPATHLEN]; | | 73 | static char dvname_store[MAXPATHLEN]; |
74 | static const char *cmdname; | | 74 | static const char *cmdname; |
75 | static int print_numbers = 0; | | 75 | static int print_numbers = 0; |
76 | | | 76 | |
77 | static void cmd_list(int, char *[]); | | 77 | static void cmd_list(int, char *[]); |
78 | static void cmd_dump(int, char *[]); | | 78 | static void cmd_dump(int, char *[]); |
| | | 79 | static void cmd_read(int, char *[]); |
| | | 80 | static void cmd_write(int, char *[]); |
79 | | | 81 | |
80 | static const struct command commands[] = { | | 82 | static const struct command commands[] = { |
81 | { "list", | | 83 | { "list", |
82 | "[-n] [-b bus] [-d device] [-f function]", | | 84 | "[-n] [-b bus] [-d device] [-f function]", |
83 | cmd_list, | | 85 | cmd_list, |
84 | O_RDONLY }, | | 86 | O_RDONLY }, |
85 | | | 87 | |
86 | { "dump", | | 88 | { "dump", |
87 | "[-b bus] -d device [-f function]", | | 89 | "[-b bus] -d device [-f function]", |
88 | cmd_dump, | | 90 | cmd_dump, |
89 | O_RDONLY }, | | 91 | O_RDONLY }, |
90 | | | 92 | |
| | | 93 | { "read", |
| | | 94 | "[-b bus] -d device [-f function] reg", |
| | | 95 | cmd_read, |
| | | 96 | O_RDONLY }, |
| | | 97 | |
| | | 98 | { "write", |
| | | 99 | "[-b bus] -d device [-f function] reg value", |
| | | 100 | cmd_write, |
| | | 101 | O_WRONLY }, |
| | | 102 | |
91 | { 0, 0, 0, 0 }, | | 103 | { 0, 0, 0, 0 }, |
92 | }; | | 104 | }; |
93 | | | 105 | |
94 | static int parse_bdf(const char *); | | 106 | static int parse_bdf(const char *); |
| | | 107 | static u_int parse_reg(const char *); |
95 | | | 108 | |
96 | static void scan_pci(int, int, int, void (*)(u_int, u_int, u_int)); | | 109 | static void scan_pci(int, int, int, void (*)(u_int, u_int, u_int)); |
97 | | | 110 | |
98 | static void scan_pci_list(u_int, u_int, u_int); | | 111 | static void scan_pci_list(u_int, u_int, u_int); |
99 | static void scan_pci_dump(u_int, u_int, u_int); | | 112 | static void scan_pci_dump(u_int, u_int, u_int); |
100 | | | 113 | |
101 | int | | 114 | int |
102 | main(int argc, char *argv[]) | | 115 | main(int argc, char *argv[]) |
103 | { | | 116 | { |
104 | int i; | | 117 | int i; |
105 | | | 118 | |
106 | /* Must have at least: device command */ | | 119 | /* Must have at least: device command */ |
107 | if (argc < 3) | | 120 | if (argc < 3) |
| @@ -220,39 +233,143 @@ cmd_dump(int argc, char *argv[]) | | | @@ -220,39 +233,143 @@ cmd_dump(int argc, char *argv[]) |
220 | if (argc != 0) | | 233 | if (argc != 0) |
221 | usage(); | | 234 | usage(); |
222 | | | 235 | |
223 | if (bus == -1) | | 236 | if (bus == -1) |
224 | errx(EXIT_FAILURE, "dump: wildcard bus number not permitted"); | | 237 | errx(EXIT_FAILURE, "dump: wildcard bus number not permitted"); |
225 | if (dev == -1) | | 238 | if (dev == -1) |
226 | errx(EXIT_FAILURE, "dump: must specify a device number"); | | 239 | errx(EXIT_FAILURE, "dump: must specify a device number"); |
227 | if (func == -1) | | 240 | if (func == -1) |
228 | errx(EXIT_FAILURE, "dump: wildcard function number not permitted"); | | 241 | errx(EXIT_FAILURE, "dump: wildcard function number not permitted"); |
229 | | | 242 | |
230 | scan_pci(bus, dev, func, scan_pci_dump); | | 243 | scan_pci(bus, dev, func, scan_pci_dump); |
231 | } | | 244 | } |
232 | | | 245 | |
| | | 246 | static void |
| | | 247 | cmd_read(int argc, char *argv[]) |
| | | 248 | { |
| | | 249 | int bus, dev, func; |
| | | 250 | u_int reg; |
| | | 251 | pcireg_t value; |
| | | 252 | int ch; |
| | | 253 | |
| | | 254 | bus = pci_businfo.busno; |
| | | 255 | func = 0; |
| | | 256 | dev = -1; |
| | | 257 | |
| | | 258 | while ((ch = getopt(argc, argv, "b:d:f:")) != -1) { |
| | | 259 | switch (ch) { |
| | | 260 | case 'b': |
| | | 261 | bus = parse_bdf(optarg); |
| | | 262 | break; |
| | | 263 | case 'd': |
| | | 264 | dev = parse_bdf(optarg); |
| | | 265 | break; |
| | | 266 | case 'f': |
| | | 267 | func = parse_bdf(optarg); |
| | | 268 | break; |
| | | 269 | default: |
| | | 270 | usage(); |
| | | 271 | } |
| | | 272 | } |
| | | 273 | argv += optind; |
| | | 274 | argc -= optind; |
| | | 275 | |
| | | 276 | if (argc != 1) |
| | | 277 | usage(); |
| | | 278 | reg = parse_reg(argv[0]); |
| | | 279 | if (pcibus_conf_read(pcifd, bus, dev, func, reg, &value) == -1) |
| | | 280 | err(EXIT_FAILURE, "pcibus_conf_read" |
| | | 281 | "(bus %d dev %d func %d reg %u)", bus, dev, func, reg); |
| | | 282 | if (printf("%08x\n", value) < 0) |
| | | 283 | err(EXIT_FAILURE, "printf"); |
| | | 284 | } |
| | | 285 | |
| | | 286 | static void |
| | | 287 | cmd_write(int argc, char *argv[]) |
| | | 288 | { |
| | | 289 | int bus, dev, func; |
| | | 290 | u_int reg; |
| | | 291 | pcireg_t value; |
| | | 292 | int ch; |
| | | 293 | |
| | | 294 | bus = pci_businfo.busno; |
| | | 295 | func = 0; |
| | | 296 | dev = -1; |
| | | 297 | |
| | | 298 | while ((ch = getopt(argc, argv, "b:d:f:")) != -1) { |
| | | 299 | switch (ch) { |
| | | 300 | case 'b': |
| | | 301 | bus = parse_bdf(optarg); |
| | | 302 | break; |
| | | 303 | case 'd': |
| | | 304 | dev = parse_bdf(optarg); |
| | | 305 | break; |
| | | 306 | case 'f': |
| | | 307 | func = parse_bdf(optarg); |
| | | 308 | break; |
| | | 309 | default: |
| | | 310 | usage(); |
| | | 311 | } |
| | | 312 | } |
| | | 313 | argv += optind; |
| | | 314 | argc -= optind; |
| | | 315 | |
| | | 316 | if (argc != 2) |
| | | 317 | usage(); |
| | | 318 | reg = parse_reg(argv[0]); |
| | | 319 | __CTASSERT(sizeof(value) == sizeof(u_int)); |
| | | 320 | value = parse_reg(argv[1]); |
| | | 321 | if (pcibus_conf_write(pcifd, bus, dev, func, reg, value) == -1) |
| | | 322 | err(EXIT_FAILURE, "pcibus_conf_write" |
| | | 323 | "(bus %d dev %d func %d reg %u value 0x%x)", |
| | | 324 | bus, dev, func, reg, value); |
| | | 325 | } |
| | | 326 | |
233 | static int | | 327 | static int |
234 | parse_bdf(const char *str) | | 328 | parse_bdf(const char *str) |
235 | { | | 329 | { |
236 | long value; | | 330 | long value; |
237 | char *end; | | 331 | char *end; |
238 | | | 332 | |
239 | if (strcmp(str, "all") == 0 || | | 333 | if (strcmp(str, "all") == 0 || |
240 | strcmp(str, "any") == 0) | | 334 | strcmp(str, "any") == 0) |
241 | return (-1); | | 335 | return (-1); |
242 | | | 336 | |
| | | 337 | errno = 0; |
243 | value = strtol(str, &end, 0); | | 338 | value = strtol(str, &end, 0); |
244 | if (*end != '\0') | | 339 | if ((str[0] == '\0') || (*end != '\0')) |
| | | 340 | errx(EXIT_FAILURE, "\"%s\" is not a number", str); |
| | | 341 | if ((errno == ERANGE) && ((value == LONG_MIN) || (value == LONG_MAX))) |
| | | 342 | errx(EXIT_FAILURE, "out of range: %s", str); |
| | | 343 | if ((value < INT_MIN) || (INT_MAX < value)) |
| | | 344 | errx(EXIT_FAILURE, "out of range: %lu", value); |
| | | 345 | |
| | | 346 | return value; |
| | | 347 | } |
| | | 348 | |
| | | 349 | static u_int |
| | | 350 | parse_reg(const char *str) |
| | | 351 | { |
| | | 352 | unsigned long value; |
| | | 353 | char *end; |
| | | 354 | |
| | | 355 | errno = 0; |
| | | 356 | value = strtoul(str, &end, 0); |
| | | 357 | if (*end != '\0') |
245 | errx(EXIT_FAILURE, "\"%s\" is not a number", str); | | 358 | errx(EXIT_FAILURE, "\"%s\" is not a number", str); |
| | | 359 | if ((errno == ERANGE) && (value == ULONG_MAX)) |
| | | 360 | errx(EXIT_FAILURE, "out of range: %s", str); |
| | | 361 | if (UINT_MAX < value) |
| | | 362 | errx(EXIT_FAILURE, "out of range: %lu", value); |
246 | | | 363 | |
247 | return value; | | 364 | return value; |
248 | } | | 365 | } |
249 | | | 366 | |
250 | static void | | 367 | static void |
251 | scan_pci(int busarg, int devarg, int funcarg, void (*cb)(u_int, u_int, u_int)) | | 368 | scan_pci(int busarg, int devarg, int funcarg, void (*cb)(u_int, u_int, u_int)) |
252 | { | | 369 | { |
253 | u_int busmin, busmax; | | 370 | u_int busmin, busmax; |
254 | u_int devmin, devmax; | | 371 | u_int devmin, devmax; |
255 | u_int funcmin, funcmax; | | 372 | u_int funcmin, funcmax; |
256 | u_int bus, dev, func; | | 373 | u_int bus, dev, func; |
257 | pcireg_t id, bhlcr; | | 374 | pcireg_t id, bhlcr; |
258 | | | 375 | |