kernel - Reduce lwp_signotify() latency
[dragonfly.git] / usr.sbin / pciconf / cap.c
1 /*-
2  * Copyright (c) 2007 Yahoo!, Inc.
3  * All rights reserved.
4  * Written by: John Baldwin <jhb@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the author nor the names of any co-contributors
15  *    may be used to endorse or promote products derived from this software
16  *    without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/usr.sbin/pciconf/cap.c,v 1.11 2010/09/16 16:03:12 jhb Exp $
31  */
32
33 #include <sys/types.h>
34
35 #include <err.h>
36 #include <stdio.h>
37 #include <sys/agpio.h>
38 #include <sys/pciio.h>
39
40 #include <dev/agp/agpreg.h>
41 #include <bus/pci/pcireg.h>
42
43 #include "pciconf.h"
44
45 static void     list_ecaps(int fd, struct pci_conf *p);
46
47 static void
48 cap_power(int fd, struct pci_conf *p, uint8_t ptr)
49 {
50         uint16_t cap, status;
51
52         cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2);
53         status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2);
54         printf("powerspec %d  supports D0%s%s D3  current D%d",
55             cap & PCIM_PCAP_SPEC,
56             cap & PCIM_PCAP_D1SUPP ? " D1" : "",
57             cap & PCIM_PCAP_D2SUPP ? " D2" : "",
58             status & PCIM_PSTAT_DMASK);
59 }
60
61 static void
62 cap_agp(int fd, struct pci_conf *p, uint8_t ptr)
63 {
64         uint32_t status, command;
65
66         status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4);
67         command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4);
68         printf("AGP ");
69         if (AGP_MODE_GET_MODE_3(status)) {
70                 printf("v3 ");
71                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x)
72                         printf("8x ");
73                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x)
74                         printf("4x ");
75         } else {
76                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x)
77                         printf("4x ");
78                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x)
79                         printf("2x ");
80                 if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x)
81                         printf("1x ");
82         }
83         if (AGP_MODE_GET_SBA(status))
84                 printf("SBA ");
85         if (AGP_MODE_GET_AGP(command)) {
86                 printf("enabled at ");
87                 if (AGP_MODE_GET_MODE_3(command)) {
88                         printf("v3 ");
89                         switch (AGP_MODE_GET_RATE(command)) {
90                         case AGP_MODE_V3_RATE_8x:
91                                 printf("8x ");
92                                 break;
93                         case AGP_MODE_V3_RATE_4x:
94                                 printf("4x ");
95                                 break;
96                         }
97                 } else
98                         switch (AGP_MODE_GET_RATE(command)) {
99                         case AGP_MODE_V2_RATE_4x:
100                                 printf("4x ");
101                                 break;
102                         case AGP_MODE_V2_RATE_2x:
103                                 printf("2x ");
104                                 break;
105                         case AGP_MODE_V2_RATE_1x:
106                                 printf("1x ");
107                                 break;
108                         }
109                 if (AGP_MODE_GET_SBA(command))
110                         printf("SBA ");
111         } else
112                 printf("disabled");
113 }
114
115 static void
116 cap_vpd(int fd __unused, struct pci_conf *p __unused, uint8_t ptr __unused)
117 {
118
119         printf("VPD");
120 }
121
122 static void
123 cap_msi(int fd, struct pci_conf *p, uint8_t ptr)
124 {
125         uint16_t ctrl;
126         int msgnum;
127
128         ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2);
129         msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1);
130         printf("MSI supports %d message%s%s%s ", msgnum,
131             (msgnum == 1) ? "" : "s",
132             (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "",
133             (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : "");
134         if (ctrl & PCIM_MSICTRL_MSI_ENABLE) {
135                 msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4);
136                 printf("enabled with %d message%s", msgnum,
137                     (msgnum == 1) ? "" : "s");
138         }
139 }
140
141 static void
142 cap_pcix(int fd, struct pci_conf *p, uint8_t ptr)
143 {
144         uint32_t status;
145         int comma, max_splits = 0, max_burst_read = 0;
146
147         status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4);
148         printf("PCI-X ");
149         if (status & PCIXM_STATUS_64BIT)
150                 printf("64-bit ");
151         if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
152                 printf("bridge ");
153         if ((p->pc_hdr & PCIM_HDRTYPE) != 1 || (status & (PCIXM_STATUS_133CAP |
154             PCIXM_STATUS_266CAP | PCIXM_STATUS_533CAP)) != 0)
155                 printf("supports");
156         comma = 0;
157         if (status & PCIXM_STATUS_133CAP) {
158                 printf("%s 133MHz", comma ? "," : "");
159                 comma = 1;
160         }
161         if (status & PCIXM_STATUS_266CAP) {
162                 printf("%s 266MHz", comma ? "," : "");
163                 comma = 1;
164         }
165         if (status & PCIXM_STATUS_533CAP) {
166                 printf("%s 533MHz", comma ? "," : "");
167                 comma = 1;
168         }
169         if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
170                 return;
171         switch (status & PCIXM_STATUS_MAX_READ) {
172         case PCIXM_STATUS_MAX_READ_512:
173                 max_burst_read = 512;
174                 break;
175         case PCIXM_STATUS_MAX_READ_1024:
176                 max_burst_read = 1024;
177                 break;
178         case PCIXM_STATUS_MAX_READ_2048:
179                 max_burst_read = 2048;
180                 break;
181         case PCIXM_STATUS_MAX_READ_4096:
182                 max_burst_read = 4096;
183                 break;
184         }
185         switch (status & PCIXM_STATUS_MAX_SPLITS) {
186         case PCIXM_STATUS_MAX_SPLITS_1:
187                 max_splits = 1;
188                 break;
189         case PCIXM_STATUS_MAX_SPLITS_2:
190                 max_splits = 2;
191                 break;
192         case PCIXM_STATUS_MAX_SPLITS_3:
193                 max_splits = 3;
194                 break;
195         case PCIXM_STATUS_MAX_SPLITS_4:
196                 max_splits = 4;
197                 break;
198         case PCIXM_STATUS_MAX_SPLITS_8:
199                 max_splits = 8;
200                 break;
201         case PCIXM_STATUS_MAX_SPLITS_12:
202                 max_splits = 12;
203                 break;
204         case PCIXM_STATUS_MAX_SPLITS_16:
205                 max_splits = 16;
206                 break;
207         case PCIXM_STATUS_MAX_SPLITS_32:
208                 max_splits = 32;
209                 break;
210         }
211         printf("%s %d burst read, %d split transaction%s", comma ? "," : "",
212             max_burst_read, max_splits, max_splits == 1 ? "" : "s");
213 }
214
215 static void
216 cap_ht(int fd, struct pci_conf *p, uint8_t ptr)
217 {
218         uint32_t reg;
219         uint16_t command;
220
221         command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2);
222         printf("HT ");
223         if ((command & 0xe000) == PCIM_HTCAP_SLAVE)
224                 printf("slave");
225         else if ((command & 0xe000) == PCIM_HTCAP_HOST)
226                 printf("host");
227         else
228                 switch (command & PCIM_HTCMD_CAP_MASK) {
229                 case PCIM_HTCAP_SWITCH:
230                         printf("switch");
231                         break;
232                 case PCIM_HTCAP_INTERRUPT:
233                         printf("interrupt");
234                         break;
235                 case PCIM_HTCAP_REVISION_ID:
236                         printf("revision ID");
237                         break;
238                 case PCIM_HTCAP_UNITID_CLUMPING:
239                         printf("unit ID clumping");
240                         break;
241                 case PCIM_HTCAP_EXT_CONFIG_SPACE:
242                         printf("extended config space");
243                         break;
244                 case PCIM_HTCAP_ADDRESS_MAPPING:
245                         printf("address mapping");
246                         break;
247                 case PCIM_HTCAP_MSI_MAPPING:
248                         printf("MSI %saddress window %s at 0x",
249                             command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "",
250                             command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
251                             "disabled");
252                         if (command & PCIM_HTCMD_MSI_FIXED)
253                                 printf("fee00000");
254                         else {
255                                 reg = read_config(fd, &p->pc_sel,
256                                     ptr + PCIR_HTMSI_ADDRESS_HI, 4);
257                                 if (reg != 0)
258                                         printf("%08x", reg);
259                                 reg = read_config(fd, &p->pc_sel,
260                                     ptr + PCIR_HTMSI_ADDRESS_LO, 4);
261                                 printf("%08x", reg);
262                         }
263                         break;
264                 case PCIM_HTCAP_DIRECT_ROUTE:
265                         printf("direct route");
266                         break;
267                 case PCIM_HTCAP_VCSET:
268                         printf("VC set");
269                         break;
270                 case PCIM_HTCAP_RETRY_MODE:
271                         printf("retry mode");
272                         break;
273                 case PCIM_HTCAP_X86_ENCODING:
274                         printf("X86 encoding");
275                         break;
276                 default:
277                         printf("unknown %02x", command);
278                         break;
279                 }
280 }
281
282 static void
283 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr)
284 {
285         uint8_t length;
286
287         length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1);
288         printf("vendor (length %d)", length);
289         if (p->pc_vendor == 0x8086) {
290                 /* Intel */
291                 uint8_t version;
292
293                 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA,
294                     1);
295                 printf(" Intel cap %d version %d", version >> 4, version & 0xf);
296                 if (version >> 4 == 1 && length == 12) {
297                         /* Feature Detection */
298                         uint32_t fvec;
299                         int comma;
300
301                         comma = 0;
302                         fvec = read_config(fd, &p->pc_sel, ptr +
303                             PCIR_VENDOR_DATA + 5, 4);
304                         printf("\n\t\t features:");
305                         if (fvec & (1 << 0)) {
306                                 printf(" AMT");
307                                 comma = 1;
308                         }
309                         fvec = read_config(fd, &p->pc_sel, ptr +
310                             PCIR_VENDOR_DATA + 1, 4);
311                         if (fvec & (1 << 21)) {
312                                 printf("%s Quick Resume", comma ? "," : "");
313                                 comma = 1;
314                         }
315                         if (fvec & (1 << 18)) {
316                                 printf("%s SATA RAID-5", comma ? "," : "");
317                                 comma = 1;
318                         }
319                         if (fvec & (1 << 9)) {
320                                 printf("%s Mobile", comma ? "," : "");
321                                 comma = 1;
322                         }
323                         if (fvec & (1 << 7)) {
324                                 printf("%s 6 PCI-e x1 slots", comma ? "," : "");
325                                 comma = 1;
326                         } else {
327                                 printf("%s 4 PCI-e x1 slots", comma ? "," : "");
328                                 comma = 1;
329                         }
330                         if (fvec & (1 << 5)) {
331                                 printf("%s SATA RAID-0/1/10", comma ? "," : "");
332                                 comma = 1;
333                         }
334                         if (fvec & (1 << 3)) {
335                                 printf("%s SATA AHCI", comma ? "," : "");
336                                 comma = 1;
337                         }
338                 }
339         }
340 }
341
342 static void
343 cap_debug(int fd, struct pci_conf *p, uint8_t ptr)
344 {
345         uint16_t debug_port;
346
347         debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2);
348         printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port &
349             PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13));
350 }
351
352 static void
353 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
354 {
355         uint32_t id;
356
357         id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4);
358         printf("PCI Bridge card=0x%08x", id);
359 }
360
361 #define MAX_PAYLOAD(field)              (128 << (field))
362
363 static void
364 cap_express(int fd, struct pci_conf *p, uint8_t ptr)
365 {
366         uint32_t val;
367         uint16_t flags;
368
369         flags = read_config(fd, &p->pc_sel, ptr + PCIER_CAPABILITY, 2);
370         printf("PCI-Express %d ", flags & PCIEM_CAP_VER_MASK);
371         switch (flags & PCIEM_CAP_PORT_TYPE) {
372         case PCIE_END_POINT:
373                 printf("endpoint");
374                 break;
375         case PCIE_LEG_END_POINT:
376                 printf("legacy endpoint");
377                 break;
378         case PCIE_ROOT_PORT:
379                 printf("root port");
380                 break;
381         case PCIE_UP_STREAM_PORT:
382                 printf("upstream port");
383                 break;
384         case PCIE_DOWN_STREAM_PORT:
385                 printf("downstream port");
386                 break;
387         case PCIE_PCIE2PCI_BRIDGE:
388                 printf("PCI bridge");
389                 break;
390         case PCIE_PCI2PCIE_BRIDGE:
391                 printf("PCI to PCIe bridge");
392                 break;
393         case PCIE_ROOT_END_POINT:
394                 printf("root endpoint");
395                 break;
396         case PCIE_ROOT_EVT_COLL:
397                 printf("event collector");
398                 break;
399         default:
400                 printf("type %d", (flags & PCIEM_CAP_PORT_TYPE) >> 8);
401                 break;
402         }
403         if (flags & PCIEM_CAP_IRQ_MSGNO)
404                 printf(" IRQ %d", (flags & PCIEM_CAP_IRQ_MSGNO) >> 8);
405         val = read_config(fd, &p->pc_sel, ptr + PCIER_DEVCAP, 4);
406         flags = read_config(fd, &p->pc_sel, ptr + PCIER_DEVCTRL, 2);
407         printf(" max data %d(%d)",
408             MAX_PAYLOAD((flags & PCIEM_DEVCAP_MAX_PAYLOAD) >> 5),
409             MAX_PAYLOAD(val & PCIEM_DEVCAP_MAX_PAYLOAD));
410         val = read_config(fd, &p->pc_sel, ptr + PCIER_LINKCAP, 4);
411         flags = read_config(fd, &p->pc_sel, ptr+ PCIER_LINKSTAT, 2);
412         printf(" link x%d(x%d)", (flags & PCIEM_LNKSTAT_WIDTH) >> 4,
413             (val & PCIEM_LNKCAP_MAXW_MASK) >> 4);
414 }
415
416 static void
417 cap_msix(int fd, struct pci_conf *p, uint8_t ptr)
418 {
419         uint32_t val;
420         uint16_t ctrl;
421         int msgnum, table_bar, pba_bar;
422
423         ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
424         msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
425         val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
426         table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
427         val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
428         pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
429         printf("MSI-X supports %d message%s ", msgnum,
430             (msgnum == 1) ? "" : "s");
431         if (table_bar == pba_bar)
432                 printf("in map 0x%x", table_bar);
433         else
434                 printf("in maps 0x%x and 0x%x", table_bar, pba_bar);
435         if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE)
436                 printf(" enabled");
437 }
438
439 static void
440 cap_sata(__unused int fd, __unused struct pci_conf *p, __unused uint8_t ptr)
441 {
442
443         printf("SATA Index-Data Pair");
444 }
445
446 static void
447 cap_pciaf(int fd, struct pci_conf *p, uint8_t ptr)
448 {
449         uint8_t cap;
450
451         cap = read_config(fd, &p->pc_sel, ptr + PCIR_PCIAF_CAP, 1);
452         printf("PCI Advanced Features:%s%s",
453             cap & PCIM_PCIAFCAP_FLR ? " FLR" : "",
454             cap & PCIM_PCIAFCAP_TP  ? " TP"  : "");
455 }
456
457 void
458 list_caps(int fd, struct pci_conf *p)
459 {
460         int express;
461         uint16_t sta;
462         uint8_t ptr, cap;
463
464         /* Are capabilities present for this device? */
465         sta = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
466         if (!(sta & PCIM_STATUS_CAPPRESENT))
467                 return;
468
469         switch (p->pc_hdr & PCIM_HDRTYPE) {
470         case PCIM_HDRTYPE_NORMAL:
471         case PCIM_HDRTYPE_BRIDGE:
472                 ptr = PCIR_CAP_PTR;
473                 break;
474         case PCIM_HDRTYPE_CARDBUS:
475                 ptr = PCIR_CAP_PTR_2;
476                 break;
477         default:
478                 errx(1, "list_caps: bad header type");
479         }
480
481         /* Walk the capability list. */
482         express = 0;
483         ptr = read_config(fd, &p->pc_sel, ptr, 1);
484         while (ptr != 0 && ptr != 0xff) {
485                 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
486                 printf("    cap %02x[%02x] = ", cap, ptr);
487                 switch (cap) {
488                 case PCIY_PMG:
489                         cap_power(fd, p, ptr);
490                         break;
491                 case PCIY_AGP:
492                         cap_agp(fd, p, ptr);
493                         break;
494                 case PCIY_VPD:
495                         cap_vpd(fd, p, ptr);
496                         break;
497                 case PCIY_MSI:
498                         cap_msi(fd, p, ptr);
499                         break;
500                 case PCIY_PCIX:
501                         cap_pcix(fd, p, ptr);
502                         break;
503                 case PCIY_HT:
504                         cap_ht(fd, p, ptr);
505                         break;
506                 case PCIY_VENDOR:
507                         cap_vendor(fd, p, ptr);
508                         break;
509                 case PCIY_DEBUG:
510                         cap_debug(fd, p, ptr);
511                         break;
512                 case PCIY_SUBVENDOR:
513                         cap_subvendor(fd, p, ptr);
514                         break;
515                 case PCIY_EXPRESS:
516                         express = 1;
517                         cap_express(fd, p, ptr);
518                         break;
519                 case PCIY_MSIX:
520                         cap_msix(fd, p, ptr);
521                         break;
522                 case PCIY_SATA:
523                         cap_sata(fd, p, ptr);
524                         break;
525                 case PCIY_PCIAF:
526                         cap_pciaf(fd, p, ptr);
527                         break;
528                 default:
529                         printf("unknown");
530                         break;
531                 }
532                 printf("\n");
533                 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
534         }
535
536         if (express)
537                 list_ecaps(fd, p);
538 }
539
540 /* From <sys/systm.h>. */
541 static __inline uint32_t
542 bitcount32(uint32_t x)
543 {
544
545         x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
546         x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
547         x = (x + (x >> 4)) & 0x0f0f0f0f;
548         x = (x + (x >> 8));
549         x = (x + (x >> 16)) & 0x000000ff;
550         return (x);
551 }
552
553 static void
554 ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
555 {
556         uint32_t sta, mask;
557
558         printf("AER %d", ver);
559         if (ver != 1)
560                 return;
561         sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4);
562         mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4);
563         printf(" %d fatal", bitcount32(sta & mask));
564         printf(" %d non-fatal", bitcount32(sta & ~mask));
565         sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4);
566         printf(" %d corrected", bitcount32(sta));
567 }
568
569 static void
570 ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
571 {
572         uint32_t cap1;
573
574         printf("VC %d", ver);
575         if (ver != 1)
576                 return;
577         cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4);
578         printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT);
579         if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0)
580                 printf(" lowpri VC0-VC%d",
581                     (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4);
582 }
583
584 static void
585 ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver)
586 {
587         uint32_t high, low;
588
589         printf("Serial %d", ver);
590         if (ver != 1)
591                 return;
592         low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4);
593         high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4);
594         printf(" %08x%08x", high, low);
595 }
596
597 static void
598 list_ecaps(int fd, struct pci_conf *p)
599 {
600         uint32_t ecap;
601         uint16_t ptr;
602
603         ptr = PCIR_EXTCAP;
604         ecap = read_config(fd, &p->pc_sel, ptr, 4);
605         if (ecap == 0xffffffff || ecap == 0)
606                 return;
607         for (;;) {
608                 printf("ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr);
609                 switch (PCI_EXTCAP_ID(ecap)) {
610                 case PCIZ_AER:
611                         ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap));
612                         break;
613                 case PCIZ_VC:
614                         ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap));
615                         break;
616                 case PCIZ_SERNUM:
617                         ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap));
618                         break;
619                 default:
620                         printf("unknown %d", PCI_EXTCAP_VER(ecap));
621                         break;
622                 }
623                 printf("\n");
624                 ptr = PCI_EXTCAP_NEXTPTR(ecap);
625                 if (ptr == 0)
626                         break;
627                 ecap = read_config(fd, &p->pc_sel, ptr, 4);
628         }
629 }