]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pciconf/cap.c
Update to bmake-20240108
[FreeBSD/FreeBSD.git] / usr.sbin / pciconf / cap.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2007 Yahoo!, Inc.
5  * All rights reserved.
6  * Written by: John Baldwin <jhb@FreeBSD.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include <sys/types.h>
34
35 #include <err.h>
36 #include <stdio.h>
37 #include <strings.h>
38 #include <sys/agpio.h>
39 #include <sys/pciio.h>
40
41 #include <dev/agp/agpreg.h>
42 #include <dev/pci/pcireg.h>
43
44 #include "pciconf.h"
45
46 static void     list_ecaps(int fd, struct pci_conf *p);
47
48 static int cap_level;
49
50 static void
51 cap_power(int fd, struct pci_conf *p, uint8_t ptr)
52 {
53         uint16_t cap, status;
54
55         cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2);
56         status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2);
57         printf("powerspec %d  supports D0%s%s D3  current D%d",
58             cap & PCIM_PCAP_SPEC,
59             cap & PCIM_PCAP_D1SUPP ? " D1" : "",
60             cap & PCIM_PCAP_D2SUPP ? " D2" : "",
61             status & PCIM_PSTAT_DMASK);
62 }
63
64 static void
65 cap_agp(int fd, struct pci_conf *p, uint8_t ptr)
66 {
67         uint32_t status, command;
68
69         status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4);
70         command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4);
71         printf("AGP ");
72         if (AGP_MODE_GET_MODE_3(status)) {
73                 printf("v3 ");
74                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x)
75                         printf("8x ");
76                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x)
77                         printf("4x ");
78         } else {
79                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x)
80                         printf("4x ");
81                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x)
82                         printf("2x ");
83                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x)
84                         printf("1x ");
85         }
86         if (AGP_MODE_GET_SBA(status))
87                 printf("SBA ");
88         if (AGP_MODE_GET_AGP(command)) {
89                 printf("enabled at ");
90                 if (AGP_MODE_GET_MODE_3(command)) {
91                         printf("v3 ");
92                         switch (AGP_MODE_GET_RATE(command)) {
93                         case AGP_MODE_V3_RATE_8x:
94                                 printf("8x ");
95                                 break;
96                         case AGP_MODE_V3_RATE_4x:
97                                 printf("4x ");
98                                 break;
99                         }
100                 } else
101                         switch (AGP_MODE_GET_RATE(command)) {
102                         case AGP_MODE_V2_RATE_4x:
103                                 printf("4x ");
104                                 break;
105                         case AGP_MODE_V2_RATE_2x:
106                                 printf("2x ");
107                                 break;
108                         case AGP_MODE_V2_RATE_1x:
109                                 printf("1x ");
110                                 break;
111                         }
112                 if (AGP_MODE_GET_SBA(command))
113                         printf("SBA ");
114         } else
115                 printf("disabled");
116 }
117
118 static void
119 cap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused)
120 {
121
122         printf("VPD");
123 }
124
125 static void
126 cap_msi(int fd, struct pci_conf *p, uint8_t ptr)
127 {
128         uint16_t ctrl;
129         int msgnum;
130
131         ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2);
132         msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1);
133         printf("MSI supports %d message%s%s%s ", msgnum,
134             (msgnum == 1) ? "" : "s",
135             (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "",
136             (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : "");
137         if (ctrl & PCIM_MSICTRL_MSI_ENABLE) {
138                 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4);
139                 printf("enabled with %d message%s", msgnum,
140                     (msgnum == 1) ? "" : "s");
141         }
142 }
143
144 static void
145 cap_pcix(int fd, struct pci_conf *p, uint8_t ptr)
146 {
147         uint32_t status;
148         int comma, max_splits, max_burst_read;
149
150         status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4);
151         printf("PCI-X ");
152         if (status & PCIXM_STATUS_64BIT)
153                 printf("64-bit ");
154         if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
155                 printf("bridge ");
156         if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP |
157             PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0)
158                 printf("supports");
159         comma = 0;
160         if (status & PCIXM_STATUS_133CAP) {
161                 printf(" 133MHz");
162                 comma = 1;
163         }
164         if (status & PCIXM_STATUS_266CAP) {
165                 printf("%s 266MHz", comma ? "," : "");
166                 comma = 1;
167         }
168         if (status & PCIXM_STATUS_533CAP) {
169                 printf("%s 533MHz", comma ? "," : "");
170                 comma = 1;
171         }
172         if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
173                 return;
174         max_burst_read = 0;
175         switch (status & PCIXM_STATUS_MAX_READ) {
176         case PCIXM_STATUS_MAX_READ_512:
177                 max_burst_read = 512;
178                 break;
179         case PCIXM_STATUS_MAX_READ_1024:
180                 max_burst_read = 1024;
181                 break;
182         case PCIXM_STATUS_MAX_READ_2048:
183                 max_burst_read = 2048;
184                 break;
185         case PCIXM_STATUS_MAX_READ_4096:
186                 max_burst_read = 4096;
187                 break;
188         }
189         max_splits = 0;
190         switch (status & PCIXM_STATUS_MAX_SPLITS) {
191         case PCIXM_STATUS_MAX_SPLITS_1:
192                 max_splits = 1;
193                 break;
194         case PCIXM_STATUS_MAX_SPLITS_2:
195                 max_splits = 2;
196                 break;
197         case PCIXM_STATUS_MAX_SPLITS_3:
198                 max_splits = 3;
199                 break;
200         case PCIXM_STATUS_MAX_SPLITS_4:
201                 max_splits = 4;
202                 break;
203         case PCIXM_STATUS_MAX_SPLITS_8:
204                 max_splits = 8;
205                 break;
206         case PCIXM_STATUS_MAX_SPLITS_12:
207                 max_splits = 12;
208                 break;
209         case PCIXM_STATUS_MAX_SPLITS_16:
210                 max_splits = 16;
211                 break;
212         case PCIXM_STATUS_MAX_SPLITS_32:
213                 max_splits = 32;
214                 break;
215         }
216         printf("%s %d burst read, %d split transaction%s", comma ? "," : "",
217             max_burst_read, max_splits, max_splits == 1 ? "" : "s");
218 }
219
220 static void
221 cap_ht(int fd, struct pci_conf *p, uint8_t ptr)
222 {
223         uint32_t reg;
224         uint16_t command;
225
226         command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2);
227         printf("HT ");
228         if ((command & 0xe000) == PCIM_HTCAP_SLAVE)
229                 printf("slave");
230         else if ((command & 0xe000) == PCIM_HTCAP_HOST)
231                 printf("host");
232         else
233                 switch (command & PCIM_HTCMD_CAP_MASK) {
234                 case PCIM_HTCAP_SWITCH:
235                         printf("switch");
236                         break;
237                 case PCIM_HTCAP_INTERRUPT:
238                         printf("interrupt");
239                         break;
240                 case PCIM_HTCAP_REVISION_ID:
241                         printf("revision ID");
242                         break;
243                 case PCIM_HTCAP_UNITID_CLUMPING:
244                         printf("unit ID clumping");
245                         break;
246                 case PCIM_HTCAP_EXT_CONFIG_SPACE:
247                         printf("extended config space");
248                         break;
249                 case PCIM_HTCAP_ADDRESS_MAPPING:
250                         printf("address mapping");
251                         break;
252                 case PCIM_HTCAP_MSI_MAPPING:
253                         printf("MSI %saddress window %s at 0x",
254                             command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "",
255                             command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
256                             "disabled");
257                         if (command & PCIM_HTCMD_MSI_FIXED)
258                                 printf("fee00000");
259                         else {
260                                 reg = read_config(fd, &p->pc_sel,
261                                     ptr + PCIR_HTMSI_ADDRESS_HI, 4);
262                                 if (reg != 0)
263                                         printf("%08x", reg);
264                                 reg = read_config(fd, &p->pc_sel,
265                                     ptr + PCIR_HTMSI_ADDRESS_LO, 4);
266                                 printf("%08x", reg);
267                         }
268                         break;
269                 case PCIM_HTCAP_DIRECT_ROUTE:
270                         printf("direct route");
271                         break;
272                 case PCIM_HTCAP_VCSET:
273                         printf("VC set");
274                         break;
275                 case PCIM_HTCAP_RETRY_MODE:
276                         printf("retry mode");
277                         break;
278                 case PCIM_HTCAP_X86_ENCODING:
279                         printf("X86 encoding");
280                         break;
281                 case PCIM_HTCAP_GEN3:
282                         printf("Gen3");
283                         break;
284                 case PCIM_HTCAP_FLE:
285                         printf("function-level extension");
286                         break;
287                 case PCIM_HTCAP_PM:
288                         printf("power management");
289                         break;
290                 case PCIM_HTCAP_HIGH_NODE_COUNT:
291                         printf("high node count");
292                         break;
293                 default:
294                         printf("unknown %02x", command);
295                         break;
296                 }
297 }
298
299 static void
300 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr)
301 {
302         uint8_t length;
303
304         length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1);
305         printf("vendor (length %d)", length);
306         if (p->pc_vendor == 0x8086) {
307                 /* Intel */
308                 uint8_t version;
309
310                 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA,
311                     1);
312                 printf(" Intel cap %d version %d", version >> 4, version & 0xf);
313                 if (version >> 4 == 1 && length == 12) {
314                         /* Feature Detection */
315                         uint32_t fvec;
316                         int comma;
317
318                         comma = 0;
319                         fvec = read_config(fd, &p->pc_sel, ptr +
320                             PCIR_VENDOR_DATA + 5, 4);
321                         printf("\n\t\t features:");
322                         if (fvec & (1 << 0)) {
323                                 printf(" AMT");
324                                 comma = 1;
325                         }
326                         fvec = read_config(fd, &p->pc_sel, ptr +
327                             PCIR_VENDOR_DATA + 1, 4);
328                         if (fvec & (1 << 21)) {
329                                 printf("%s Quick Resume", comma ? "," : "");
330                                 comma = 1;
331                         }
332                         if (fvec & (1 << 18)) {
333                                 printf("%s SATA RAID-5", comma ? "," : "");
334                                 comma = 1;
335                         }
336                         if (fvec & (1 << 9)) {
337                                 printf("%s Mobile", comma ? "," : "");
338                                 comma = 1;
339                         }
340                         if (fvec & (1 << 7)) {
341                                 printf("%s 6 PCI-e x1 slots", comma ? "," : "");
342                                 comma = 1;
343                         } else {
344                                 printf("%s 4 PCI-e x1 slots", comma ? "," : "");
345                                 comma = 1;
346                         }
347                         if (fvec & (1 << 5)) {
348                                 printf("%s SATA RAID-0/1/10", comma ? "," : "");
349                                 comma = 1;
350                         }
351                         if (fvec & (1 << 3))
352                                 printf(", SATA AHCI");
353                 }
354         }
355 }
356
357 static void
358 cap_debug(int fd, struct pci_conf *p, uint8_t ptr)
359 {
360         uint16_t debug_port;
361
362         debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2);
363         printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port &
364             PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13));
365 }
366
367 static void
368 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
369 {
370         uint32_t id;
371         uint16_t ssid, ssvid;
372
373         id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4);
374         ssid = id >> 16;
375         ssvid = id & 0xffff;
376         printf("PCI Bridge subvendor=0x%04x subdevice=0x%04x", ssvid, ssid);
377 }
378
379 #define MAX_PAYLOAD(field)              (128 << (field))
380
381 static const char *
382 link_speed_string(uint8_t speed)
383 {
384
385         switch (speed) {
386         case 1:
387                 return ("2.5");
388         case 2:
389                 return ("5.0");
390         case 3:
391                 return ("8.0");
392         case 4:
393                 return ("16.0");
394         case 5:
395                 return ("32.0");
396         case 6:
397                 return ("64.0");
398         default:
399                 return ("undef");
400         }
401 }
402
403 static const char *
404 max_read_string(u_int max_read)
405 {
406
407         switch (max_read) {
408         case 0x0:
409                 return ("128");
410         case 0x1:
411                 return ("256");
412         case 0x2:
413                 return ("512");
414         case 0x3:
415                 return ("1024");
416         case 0x4:
417                 return ("2048");
418         case 0x5:
419                 return ("4096");
420         default:
421                 return ("undef");
422         }
423 }
424
425 static const char *
426 aspm_string(uint8_t aspm)
427 {
428
429         switch (aspm) {
430         case 1:
431                 return ("L0s");
432         case 2:
433                 return ("L1");
434         case 3:
435                 return ("L0s/L1");
436         default:
437                 return ("disabled");
438         }
439 }
440
441 static int
442 slot_power(uint32_t cap)
443 {
444         int mwatts;
445
446         mwatts = (cap & PCIEM_SLOT_CAP_SPLV) >> 7;
447         switch (cap & PCIEM_SLOT_CAP_SPLS) {
448         case 0x0:
449                 mwatts *= 1000;
450                 break;
451         case 0x1:
452                 mwatts *= 100;
453                 break;
454         case 0x2:
455                 mwatts *= 10;
456                 break;
457         default:
458                 break;
459         }
460         return (mwatts);
461 }
462
463 static void
464 cap_express(int fd, struct pci_conf *p, uint8_t ptr)
465 {
466         uint32_t cap;
467         uint16_t ctl, flags, sta;
468         unsigned int version;
469
470         flags = read_config(fd, &p->pc_sel, ptr + PCIER_FLAGS, 2);
471         version = flags & PCIEM_FLAGS_VERSION;
472         printf("PCI-Express %u ", version);
473         switch (flags & PCIEM_FLAGS_TYPE) {
474         case PCIEM_TYPE_ENDPOINT:
475                 printf("endpoint");
476                 break;
477         case PCIEM_TYPE_LEGACY_ENDPOINT:
478                 printf("legacy endpoint");
479                 break;
480         case PCIEM_TYPE_ROOT_PORT:
481                 printf("root port");
482                 break;
483         case PCIEM_TYPE_UPSTREAM_PORT:
484                 printf("upstream port");
485                 break;
486         case PCIEM_TYPE_DOWNSTREAM_PORT:
487                 printf("downstream port");
488                 break;
489         case PCIEM_TYPE_PCI_BRIDGE:
490                 printf("PCI bridge");
491                 break;
492         case PCIEM_TYPE_PCIE_BRIDGE:
493                 printf("PCI to PCIe bridge");
494                 break;
495         case PCIEM_TYPE_ROOT_INT_EP:
496                 printf("root endpoint");
497                 break;
498         case PCIEM_TYPE_ROOT_EC:
499                 printf("event collector");
500                 break;
501         default:
502                 printf("type %d", (flags & PCIEM_FLAGS_TYPE) >> 4);
503                 break;
504         }
505         if (flags & PCIEM_FLAGS_IRQ)
506                 printf(" MSI %d", (flags & PCIEM_FLAGS_IRQ) >> 9);
507         cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP, 4);
508         ctl = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CTL, 2);
509         printf(" max data %d(%d)",
510             MAX_PAYLOAD((ctl & PCIEM_CTL_MAX_PAYLOAD) >> 5),
511             MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD));
512         if ((cap & PCIEM_CAP_FLR) != 0)
513                 printf(" FLR");
514         if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE)
515                 printf(" RO");
516         if (ctl & PCIEM_CTL_NOSNOOP_ENABLE)
517                 printf(" NS");
518         if (version >= 2) {
519                 cap = read_config(fd, &p->pc_sel, ptr + PCIER_DEVICE_CAP2, 4);
520                 if ((cap & PCIEM_CAP2_ARI) != 0) {
521                         ctl = read_config(fd, &p->pc_sel,
522                             ptr + PCIER_DEVICE_CTL2, 4);
523                         printf(" ARI %s",
524                             (ctl & PCIEM_CTL2_ARI) ? "enabled" : "disabled");
525                 }
526         }
527         printf("\n                 max read %s", max_read_string((ctl &
528             PCIEM_CTL_MAX_READ_REQUEST) >> 12));
529         cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4);
530         sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2);
531         if (cap == 0 && sta == 0)
532                 return;
533         printf("\n                ");
534         printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4,
535             (cap & PCIEM_LINK_CAP_MAX_WIDTH) >> 4);
536         if ((cap & PCIEM_LINK_CAP_MAX_WIDTH) != 0) {
537                 printf(" speed %s(%s)", (sta & PCIEM_LINK_STA_WIDTH) == 0 ?
538                     "0.0" : link_speed_string(sta & PCIEM_LINK_STA_SPEED),
539                     link_speed_string(cap & PCIEM_LINK_CAP_MAX_SPEED));
540         }
541         if ((cap & PCIEM_LINK_CAP_ASPM) != 0) {
542                 ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2);
543                 printf(" ASPM %s(%s)", aspm_string(ctl & PCIEM_LINK_CTL_ASPMC),
544                     aspm_string((cap & PCIEM_LINK_CAP_ASPM) >> 10));
545         }
546         if ((cap & PCIEM_LINK_CAP_CLOCK_PM) != 0) {
547                 ctl = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CTL, 2);
548                 printf(" ClockPM %s", (ctl & PCIEM_LINK_CTL_ECPM) ?
549                     "enabled" : "disabled");
550         }
551         if (!(flags & PCIEM_FLAGS_SLOT))
552                 return;
553         cap = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CAP, 4);
554         sta = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_STA, 2);
555         ctl = read_config(fd, &p->pc_sel, ptr + PCIER_SLOT_CTL, 2);
556         printf("\n                ");
557         printf(" slot %d", (cap & PCIEM_SLOT_CAP_PSN) >> 19);
558         printf(" power limit %d mW", slot_power(cap));
559         if (cap & PCIEM_SLOT_CAP_HPC)
560                 printf(" HotPlug(%s)", sta & PCIEM_SLOT_STA_PDS ? "present" :
561                     "empty");
562         if (cap & PCIEM_SLOT_CAP_HPS)
563                 printf(" surprise");
564         if (cap & PCIEM_SLOT_CAP_APB)
565                 printf(" Attn Button");
566         if (cap & PCIEM_SLOT_CAP_PCP)
567                 printf(" PC(%s)", ctl & PCIEM_SLOT_CTL_PCC ? "off" : "on");
568         if (cap & PCIEM_SLOT_CAP_MRLSP)
569                 printf(" MRL(%s)", sta & PCIEM_SLOT_STA_MRLSS ? "open" :
570                     "closed");
571         if (cap & PCIEM_SLOT_CAP_EIP)
572                 printf(" EI(%s)", sta & PCIEM_SLOT_STA_EIS ? "engaged" :
573                     "disengaged");
574 }
575
576 static void
577 cap_msix(int fd, struct pci_conf *p, uint8_t ptr)
578 {
579         uint32_t pba_offset, table_offset, val;
580         int msgnum, pba_bar, table_bar;
581         uint16_t ctrl;
582
583         ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
584         msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
585
586         val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
587         table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
588         table_offset = val & ~PCIM_MSIX_BIR_MASK;
589
590         val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
591         pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
592         pba_offset = val & ~PCIM_MSIX_BIR_MASK;
593
594         printf("MSI-X supports %d message%s%s\n", msgnum,
595             (msgnum == 1) ? "" : "s",
596             (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) ? ", enabled" : "");
597
598         printf("                 ");
599         printf("Table in map 0x%x[0x%x], PBA in map 0x%x[0x%x]",
600             table_bar, table_offset, pba_bar, pba_offset);
601 }
602
603 static void
604 cap_sata(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused)
605 {
606
607         printf("SATA Index-Data Pair");
608 }
609
610 static void
611 cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr)
612 {
613         uint8_t cap;
614
615         cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1);
616         printf("PCI Advanced Features:%s%s",
617             cap & PCIM_PCIAFCAP_FLR ? " FLR" : "",
618             cap & PCIM_PCIAFCAP_TP  ? " TP"  : "");
619 }
620
621 static const char *
622 ea_bei_to_name(int bei)
623 {
624         static const char *barstr[] = {
625                 "BAR0", "BAR1", "BAR2", "BAR3", "BAR4", "BAR5"
626         };
627         static const char *vfbarstr[] = {
628                 "VFBAR0", "VFBAR1", "VFBAR2", "VFBAR3", "VFBAR4", "VFBAR5"
629         };
630
631         if ((bei >= PCIM_EA_BEI_BAR_0) && (bei <= PCIM_EA_BEI_BAR_5))
632                 return (barstr[bei - PCIM_EA_BEI_BAR_0]);
633         if ((bei >= PCIM_EA_BEI_VF_BAR_0) && (bei <= PCIM_EA_BEI_VF_BAR_5))
634                 return (vfbarstr[bei - PCIM_EA_BEI_VF_BAR_0]);
635
636         switch (bei) {
637         case PCIM_EA_BEI_BRIDGE:
638                 return "BRIDGE";
639         case PCIM_EA_BEI_ENI:
640                 return "ENI";
641         case PCIM_EA_BEI_ROM:
642                 return "ROM";
643         case PCIM_EA_BEI_RESERVED:
644         default:
645                 return "RSVD";
646         }
647 }
648
649 static const char *
650 ea_prop_to_name(uint8_t prop)
651 {
652
653         switch (prop) {
654         case PCIM_EA_P_MEM:
655                 return "Non-Prefetchable Memory";
656         case PCIM_EA_P_MEM_PREFETCH:
657                 return "Prefetchable Memory";
658         case PCIM_EA_P_IO:
659                 return "I/O Space";
660         case PCIM_EA_P_VF_MEM_PREFETCH:
661                 return "VF Prefetchable Memory";
662         case PCIM_EA_P_VF_MEM:
663                 return "VF Non-Prefetchable Memory";
664         case PCIM_EA_P_BRIDGE_MEM:
665                 return "Bridge Non-Prefetchable Memory";
666         case PCIM_EA_P_BRIDGE_MEM_PREFETCH:
667                 return "Bridge Prefetchable Memory";
668         case PCIM_EA_P_BRIDGE_IO:
669                 return "Bridge I/O Space";
670         case PCIM_EA_P_MEM_RESERVED:
671                 return "Reserved Memory";
672         case PCIM_EA_P_IO_RESERVED:
673                 return "Reserved I/O Space";
674         case PCIM_EA_P_UNAVAILABLE:
675                 return "Unavailable";
676         default:
677                 return "Reserved";
678         }
679 }
680
681 static void
682 cap_ea(int fd, struct pci_conf *p, uint8_t ptr)
683 {
684         int num_ent;
685         int a, b;
686         uint32_t bei;
687         uint32_t val;
688         int ent_size;
689         uint32_t dw[4];
690         uint32_t flags, flags_pp, flags_sp;
691         uint64_t base, max_offset;
692         uint8_t fixed_sub_bus_nr, fixed_sec_bus_nr;
693
694         /* Determine the number of entries */
695         num_ent = read_config(fd, &p->pc_sel, ptr + PCIR_EA_NUM_ENT, 2);
696         num_ent &= PCIM_EA_NUM_ENT_MASK;
697
698         printf("PCI Enhanced Allocation (%d entries)", num_ent);
699
700         /* Find the first entry to care of */
701         ptr += PCIR_EA_FIRST_ENT;
702
703         /* Print BUS numbers for bridges */
704         if ((p->pc_hdr & PCIM_HDRTYPE) == PCIM_HDRTYPE_BRIDGE) {
705                 val = read_config(fd, &p->pc_sel, ptr, 4);
706
707                 fixed_sec_bus_nr = PCIM_EA_SEC_NR(val);
708                 fixed_sub_bus_nr = PCIM_EA_SUB_NR(val);
709
710                 printf("\n\t\t BRIDGE, sec bus [%d], sub bus [%d]",
711                     fixed_sec_bus_nr, fixed_sub_bus_nr);
712                 ptr += 4;
713         }
714
715         for (a = 0; a < num_ent; a++) {
716                 /* Read a number of dwords in the entry */
717                 val = read_config(fd, &p->pc_sel, ptr, 4);
718                 ptr += 4;
719                 ent_size = (val & PCIM_EA_ES);
720
721                 for (b = 0; b < ent_size; b++) {
722                         dw[b] = read_config(fd, &p->pc_sel, ptr, 4);
723                         ptr += 4;
724                 }
725
726                 flags = val;
727                 flags_pp = (flags & PCIM_EA_PP) >> PCIM_EA_PP_OFFSET;
728                 flags_sp = (flags & PCIM_EA_SP) >> PCIM_EA_SP_OFFSET;
729                 bei = (PCIM_EA_BEI & val) >> PCIM_EA_BEI_OFFSET;
730
731                 base = dw[0] & PCIM_EA_FIELD_MASK;
732                 max_offset = dw[1] | ~PCIM_EA_FIELD_MASK;
733                 b = 2;
734                 if (((dw[0] & PCIM_EA_IS_64) != 0) && (b < ent_size)) {
735                         base |= (uint64_t)dw[b] << 32UL;
736                         b++;
737                 }
738                 if (((dw[1] & PCIM_EA_IS_64) != 0)
739                         && (b < ent_size)) {
740                         max_offset |= (uint64_t)dw[b] << 32UL;
741                         b++;
742                 }
743
744                 printf("\n\t\t [%d] %s, %s, %s, base [0x%jx], size [0x%jx]"
745                     "\n\t\t\tPrimary properties [0x%x] (%s)"
746                     "\n\t\t\tSecondary properties [0x%x] (%s)",
747                     bei, ea_bei_to_name(bei),
748                     (flags & PCIM_EA_ENABLE ? "Enabled" : "Disabled"),
749                     (flags & PCIM_EA_WRITABLE ? "Writable" : "Read-only"),
750                     (uintmax_t)base, (uintmax_t)(max_offset + 1),
751                     flags_pp, ea_prop_to_name(flags_pp),
752                     flags_sp, ea_prop_to_name(flags_sp));
753         }
754 }
755
756 void
757 list_caps(int fd, struct pci_conf *p, int level)
758 {
759         int express;
760         uint16_t sta;
761         uint8_t ptr, cap;
762
763         /* Are capabilities present for this device? */
764         sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
765         if (!(sta & PCIM_STATUS_CAPPRESENT))
766                 return;
767
768         cap_level = level;
769
770         switch (p->pc_hdr & PCIM_HDRTYPE) {
771         case PCIM_HDRTYPE_NORMAL:
772         case PCIM_HDRTYPE_BRIDGE:
773                 ptr = PCIR_CAP_PTR;
774                 break;
775         case PCIM_HDRTYPE_CARDBUS:
776                 ptr = PCIR_CAP_PTR_2;
777                 break;
778         default:
779                 errx(1, "list_caps: bad header type");
780         }
781
782         /* Walk the capability list. */
783         express = 0;
784         ptr = read_config(fd, &p->pc_sel, ptr, 1);
785         while (ptr != 0 && ptr != 0xff) {
786                 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
787                 printf("    cap %02x[%02x] = ", cap, ptr);
788                 switch (cap) {
789                 case PCIY_PMG:
790                         cap_power(fd, p, ptr);
791                         break;
792                 case PCIY_AGP:
793                         cap_agp(fd, p, ptr);
794                         break;
795                 case PCIY_VPD:
796                         cap_vpd(fd, p, ptr);
797                         break;
798                 case PCIY_MSI:
799                         cap_msi(fd, p, ptr);
800                         break;
801                 case PCIY_PCIX:
802                         cap_pcix(fd, p, ptr);
803                         break;
804                 case PCIY_HT:
805                         cap_ht(fd, p, ptr);
806                         break;
807                 case PCIY_VENDOR:
808                         cap_vendor(fd, p, ptr);
809                         break;
810                 case PCIY_DEBUG:
811                         cap_debug(fd, p, ptr);
812                         break;
813                 case PCIY_SUBVENDOR:
814                         cap_subvendor(fd, p, ptr);
815                         break;
816                 case PCIY_EXPRESS:
817                         express = 1;
818                         cap_express(fd, p, ptr);
819                         break;
820                 case PCIY_MSIX:
821                         cap_msix(fd, p, ptr);
822                         break;
823                 case PCIY_SATA:
824                         cap_sata(fd, p, ptr);
825                         break;
826                 case PCIY_PCIAF:
827                         cap_pciaf(fd, p, ptr);
828                         break;
829                 case PCIY_EA:
830                         cap_ea(fd, p, ptr);
831                         break;
832                 default:
833                         printf("unknown");
834                         break;
835                 }
836                 printf("\n");
837                 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
838         }
839
840         if (express)
841                 list_ecaps(fd, p);
842 }
843
844 /* From <sys/systm.h>. */
845 static __inline uint32_t
846 bitcount32(uint32_t x)
847 {
848
849         x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
850         x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
851         x = (x + (x >> 4)) & 0x0f0f0f0f;
852         x = (x + (x >> 8));
853         x = (x + (x >> 16)) & 0x000000ff;
854         return (x);
855 }
856
857 static void
858 ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
859 {
860         uint32_t sta, mask;
861
862         printf("AER %d", ver);
863         if (ver < 1) {
864                 printf("\n");
865                 return;
866         }
867         sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4);
868         mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4);
869         printf(" %d fatal", bitcount32(sta & mask));
870         printf(" %d non-fatal", bitcount32(sta & ~mask));
871         sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4);
872         printf(" %d corrected\n", bitcount32(sta));
873 }
874
875 static void
876 ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
877 {
878         uint32_t cap1;
879
880         printf("VC %d", ver);
881         if (ver < 1) {
882                 printf("\n");
883                 return;
884         }
885         cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4);
886         printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT);
887         if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0)
888                 printf(" lowpri VC0-VC%d",
889                     (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4);
890         printf("\n");
891 }
892
893 static void
894 ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
895 {
896         uint32_t high, low;
897
898         printf("Serial %d", ver);
899         if (ver < 1) {
900                 printf("\n");
901                 return;
902         }
903         low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4);
904         high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4);
905         printf(" %08x%08x\n", high, low);
906 }
907
908 static void
909 ecap_vendor(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
910 {
911         uint32_t val, hdr;
912         uint16_t nextptr, len;
913         int i;
914
915         val = read_config(fd, &p->pc_sel, ptr, 4);
916         nextptr = PCI_EXTCAP_NEXTPTR(val);
917         hdr = read_config(fd, &p->pc_sel, ptr + PCIR_VSEC_HEADER, 4);
918         len = PCIR_VSEC_LENGTH(hdr);
919         if (len == 0) {
920                 if (nextptr == 0)
921                         nextptr = 0x1000;
922                 len = nextptr - ptr;
923         }
924
925         printf("Vendor [%d] ID %04x Rev %d Length %d\n", ver,
926             PCIR_VSEC_ID(hdr), PCIR_VSEC_REV(hdr), len);
927         if ((ver < 1) || (cap_level <= 1))
928                 return;
929         for (i = 0; i < len; i += 4) {
930                 val = read_config(fd, &p->pc_sel, ptr + i, 4);
931                 if ((i % 16) == 0)
932                         printf("                 ");
933                 printf("%02x %02x %02x %02x", val & 0xff, (val >> 8) & 0xff,
934                     (val >> 16) & 0xff, (val >> 24) & 0xff);
935                 if ((((i + 4) % 16) == 0 ) || ((i + 4) >= len))
936                         printf("\n");
937                 else
938                         printf(" ");
939         }
940 }
941
942 static void
943 ecap_sec_pcie(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
944 {
945         uint32_t val;
946
947         printf("PCIe Sec %d", ver);
948         if (ver < 1) {
949                 printf("\n");
950                 return;
951         }
952         val = read_config(fd, &p->pc_sel, ptr + 8, 4);
953         printf(" lane errors %#x\n", val);
954 }
955
956 static const char *
957 check_enabled(int value)
958 {
959
960         return (value ? "enabled" : "disabled");
961 }
962
963 static void
964 ecap_sriov(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
965 {
966         const char *comma, *enabled;
967         uint16_t iov_ctl, total_vfs, num_vfs, vf_offset, vf_stride, vf_did;
968         uint32_t page_caps, page_size, page_shift, size;
969         int i;
970
971         printf("SR-IOV %d ", ver);
972
973         iov_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_CTL, 2);
974         printf("IOV %s, Memory Space %s, ARI %s\n",
975             check_enabled(iov_ctl & PCIM_SRIOV_VF_EN),
976             check_enabled(iov_ctl & PCIM_SRIOV_VF_MSE),
977             check_enabled(iov_ctl & PCIM_SRIOV_ARI_EN));
978
979         total_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_TOTAL_VFS, 2);
980         num_vfs = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_NUM_VFS, 2);
981         printf("                     ");
982         printf("%d VFs configured out of %d supported\n", num_vfs, total_vfs);
983
984         vf_offset = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_OFF, 2);
985         vf_stride = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_STRIDE, 2);
986         printf("                     ");
987         printf("First VF RID Offset 0x%04x, VF RID Stride 0x%04x\n", vf_offset,
988             vf_stride);
989
990         vf_did = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_VF_DID, 2);
991         printf("                     VF Device ID 0x%04x\n", vf_did);
992
993         page_caps = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_CAP, 4);
994         page_size = read_config(fd, &p->pc_sel, ptr + PCIR_SRIOV_PAGE_SIZE, 4);
995         printf("                     ");
996         printf("Page Sizes: ");
997         comma = "";
998         while (page_caps != 0) {
999                 page_shift = ffs(page_caps) - 1;
1000
1001                 if (page_caps & page_size)
1002                         enabled = " (enabled)";
1003                 else
1004                         enabled = "";
1005
1006                 size = (1 << (page_shift + PCI_SRIOV_BASE_PAGE_SHIFT));
1007                 printf("%s%d%s", comma, size, enabled);
1008                 comma = ", ";
1009
1010                 page_caps &= ~(1 << page_shift);
1011         }
1012         printf("\n");
1013
1014         for (i = 0; i <= PCIR_MAX_BAR_0; i++)
1015                 print_bar(fd, p, "iov bar  ", ptr + PCIR_SRIOV_BAR(i));
1016 }
1017
1018 static const char *
1019 check_avail_and_state(u_int cap, u_int capbit, u_int ctl, u_int ctlbit)
1020 {
1021
1022         if (cap & capbit)
1023                 return (ctl & ctlbit ? "enabled" : "disabled");
1024         else
1025                 return "unavailable";
1026 }
1027
1028 static void
1029 ecap_acs(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
1030 {
1031         uint16_t acs_cap, acs_ctl;
1032         static const char *const acc[] = { "access enabled", "blocking enabled",
1033                 "redirect enabled", "reserved" };
1034
1035         printf("ACS %d ", ver);
1036         if (ver != 1) {
1037                 printf("\n");
1038                 return;
1039         }
1040
1041 #define CHECK_AVAIL_STATE(bit) \
1042         check_avail_and_state(acs_cap, bit, acs_ctl, bit##_ENABLE)
1043
1044         acs_cap = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CAP, 2);
1045         acs_ctl = read_config(fd, &p->pc_sel, ptr + PCIR_ACS_CTL, 2);
1046         printf("Source Validation %s, Translation Blocking %s\n",
1047             CHECK_AVAIL_STATE(PCIM_ACS_SOURCE_VALIDATION),
1048             CHECK_AVAIL_STATE(PCIM_ACS_TRANSLATION_BLOCKING));
1049
1050         printf("                     ");
1051         printf("P2P Req Redirect %s, P2P Cmpl Redirect %s\n",
1052             CHECK_AVAIL_STATE(PCIM_ACS_P2P_REQ_REDIRECT),
1053             CHECK_AVAIL_STATE(PCIM_ACS_P2P_CMP_REDIRECT));
1054         printf("                     ");
1055         printf("P2P Upstream Forwarding %s, P2P Egress Control %s\n",
1056             CHECK_AVAIL_STATE(PCIM_ACS_P2P_UPSTREAM_FORWARDING),
1057             CHECK_AVAIL_STATE(PCIM_ACS_P2P_EGRESS_CTL));
1058         printf("                     ");
1059         printf("P2P Direct Translated %s, Enhanced Capability %s\n",
1060             CHECK_AVAIL_STATE(PCIM_ACS_P2P_DIRECT_TRANSLATED),
1061             acs_ctl & PCIM_ACS_ENHANCED_CAP ? "available" : "unavailable");
1062 #undef  CHECK_AVAIL_STATE
1063
1064         if (acs_cap & PCIM_ACS_ENHANCED_CAP) {
1065                 printf("                     ");
1066                 printf("I/O Req Blocking %s, Unclaimed Req Redirect Control %s\n",
1067                     check_enabled(acs_ctl & PCIM_ACS_IO_REQ_BLOCKING_ENABLE),
1068                     check_enabled(acs_ctl & PCIM_ACS_UNCLAIMED_REQ_REDIRECT_CTL));
1069                 printf("                     ");
1070                 printf("DSP BAR %s, USP BAR %s\n",
1071                     acc[(acs_cap & PCIM_ACS_DSP_MEM_TGT_ACC_CTL) >> 8],
1072                     acc[(acs_cap & PCIM_ACS_USP_MEM_TGT_ACC_CTL) >> 10]);
1073         }
1074 }
1075
1076 static struct {
1077         uint16_t id;
1078         const char *name;
1079 } ecap_names[] = {
1080         { PCIZ_AER, "AER" },
1081         { PCIZ_VC, "Virtual Channel" },
1082         { PCIZ_SERNUM, "Device Serial Number" },
1083         { PCIZ_PWRBDGT, "Power Budgeting" },
1084         { PCIZ_RCLINK_DCL, "Root Complex Link Declaration" },
1085         { PCIZ_RCLINK_CTL, "Root Complex Internal Link Control" },
1086         { PCIZ_RCEC_ASSOC, "Root Complex Event Collector ASsociation" },
1087         { PCIZ_MFVC, "MFVC" },
1088         { PCIZ_VC2, "Virtual Channel 2" },
1089         { PCIZ_RCRB, "RCRB" },
1090         { PCIZ_CAC, "Configuration Access Correction" },
1091         { PCIZ_ACS, "ACS" },
1092         { PCIZ_ARI, "ARI" },
1093         { PCIZ_ATS, "ATS" },
1094         { PCIZ_SRIOV, "SRIOV" },
1095         { PCIZ_MRIOV, "MRIOV" },
1096         { PCIZ_MULTICAST, "Multicast" },
1097         { PCIZ_PAGE_REQ, "Page Page Request" },
1098         { PCIZ_AMD, "AMD proprietary "},
1099         { PCIZ_RESIZE_BAR, "Resizable BAR" },
1100         { PCIZ_DPA, "DPA" },
1101         { PCIZ_TPH_REQ, "TPH Requester" },
1102         { PCIZ_LTR, "LTR" },
1103         { PCIZ_SEC_PCIE, "Secondary PCI Express" },
1104         { PCIZ_PMUX, "Protocol Multiplexing" },
1105         { PCIZ_PASID, "Process Address Space ID" },
1106         { PCIZ_LN_REQ, "LN Requester" },
1107         { PCIZ_DPC, "Downstream Port Containment" },
1108         { PCIZ_L1PM, "L1 PM Substates" },
1109         { PCIZ_PTM, "Precision Time Measurement" },
1110         { PCIZ_M_PCIE, "PCIe over M-PHY" },
1111         { PCIZ_FRS, "FRS Queuing" },
1112         { PCIZ_RTR, "Readiness Time Reporting" },
1113         { PCIZ_DVSEC, "Designated Vendor-Specific" },
1114         { PCIZ_VF_REBAR, "VF Resizable BAR" },
1115         { PCIZ_DLNK, "Data Link Feature" },
1116         { PCIZ_16GT, "Physical Layer 16.0 GT/s" },
1117         { PCIZ_LMR, "Lane Margining at Receiver" },
1118         { PCIZ_HIER_ID, "Hierarchy ID" },
1119         { PCIZ_NPEM, "Native PCIe Enclosure Management" },
1120         { PCIZ_PL32, "Physical Layer 32.0 GT/s" },
1121         { PCIZ_AP, "Alternate Protocol" },
1122         { PCIZ_SFI, "System Firmware Intermediary" },
1123         { 0, NULL }
1124 };
1125
1126 static void
1127 list_ecaps(int fd, struct pci_conf *p)
1128 {
1129         const char *name;
1130         uint32_t ecap;
1131         uint16_t ptr;
1132         int i;
1133
1134         ptr = PCIR_EXTCAP;
1135         ecap = read_config(fd, &p->pc_sel, ptr, 4);
1136         if (ecap == 0xffffffff || ecap == 0)
1137                 return;
1138         for (;;) {
1139                 printf("    ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr);
1140                 switch (PCI_EXTCAP_ID(ecap)) {
1141                 case PCIZ_AER:
1142                         ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1143                         break;
1144                 case PCIZ_VC:
1145                         ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1146                         break;
1147                 case PCIZ_SERNUM:
1148                         ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1149                         break;
1150                 case PCIZ_VENDOR:
1151                         ecap_vendor(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1152                         break;
1153                 case PCIZ_SEC_PCIE:
1154                         ecap_sec_pcie(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1155                         break;
1156                 case PCIZ_SRIOV:
1157                         ecap_sriov(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1158                         break;
1159                 case PCIZ_ACS:
1160                         ecap_acs(fd, p, ptr, PCI_EXTCAP_VER(ecap));
1161                         break;
1162                 default:
1163                         name = "unknown";
1164                         for (i = 0; ecap_names[i].name != NULL; i++)
1165                                 if (ecap_names[i].id == PCI_EXTCAP_ID(ecap)) {
1166                                         name = ecap_names[i].name;
1167                                         break;
1168                                 }
1169                         printf("%s %d\n", name, PCI_EXTCAP_VER(ecap));
1170                         break;
1171                 }
1172                 ptr = PCI_EXTCAP_NEXTPTR(ecap);
1173                 if (ptr == 0)
1174                         break;
1175                 ecap = read_config(fd, &p->pc_sel, ptr, 4);
1176         }
1177 }
1178
1179 /* Find offset of a specific capability.  Returns 0 on failure. */
1180 uint8_t
1181 pci_find_cap(int fd, struct pci_conf *p, uint8_t id)
1182 {
1183         uint16_t sta;
1184         uint8_t ptr, cap;
1185
1186         /* Are capabilities present for this device? */
1187         sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
1188         if (!(sta & PCIM_STATUS_CAPPRESENT))
1189                 return (0);
1190
1191         switch (p->pc_hdr & PCIM_HDRTYPE) {
1192         case PCIM_HDRTYPE_NORMAL:
1193         case PCIM_HDRTYPE_BRIDGE:
1194                 ptr = PCIR_CAP_PTR;
1195                 break;
1196         case PCIM_HDRTYPE_CARDBUS:
1197                 ptr = PCIR_CAP_PTR_2;
1198                 break;
1199         default:
1200                 return (0);
1201         }
1202
1203         ptr = read_config(fd, &p->pc_sel, ptr, 1);
1204         while (ptr != 0 && ptr != 0xff) {
1205                 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
1206                 if (cap == id)
1207                         return (ptr);
1208                 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
1209         }
1210         return (0);
1211 }
1212
1213 /* Find offset of a specific extended capability.  Returns 0 on failure. */
1214 uint16_t
1215 pcie_find_cap(int fd, struct pci_conf *p, uint16_t id)
1216 {
1217         uint32_t ecap;
1218         uint16_t ptr;
1219
1220         ptr = PCIR_EXTCAP;
1221         ecap = read_config(fd, &p->pc_sel, ptr, 4);
1222         if (ecap == 0xffffffff || ecap == 0)
1223                 return (0);
1224         for (;;) {
1225                 if (PCI_EXTCAP_ID(ecap) == id)
1226                         return (ptr);
1227                 ptr = PCI_EXTCAP_NEXTPTR(ecap);
1228                 if (ptr == 0)
1229                         break;
1230                 ecap = read_config(fd, &p->pc_sel, ptr, 4);
1231         }
1232         return (0);
1233 }