]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pciconf/cap.c
This commit was generated by cvs2svn to compensate for changes in r172767,
[FreeBSD/FreeBSD.git] / usr.sbin / pciconf / cap.c
1 /*-
2  * Copyright (c) 2007 John Baldwin <jhb@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #ifndef lint
31 static const char rcsid[] =
32   "$FreeBSD$";
33 #endif /* not lint */
34
35 #include <sys/types.h>
36
37 #include <err.h>
38 #include <stdio.h>
39 #include <sys/agpio.h>
40 #include <sys/pciio.h>
41
42 #include <pci/agpreg.h>
43 #include <dev/pci/pcireg.h>
44
45 #include "pciconf.h"
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, struct pci_conf *p, uint8_t ptr)
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, max_burst_read;
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         printf("supports");
154         comma = 0;
155         if (status & PCIXM_STATUS_133CAP) {
156                 printf("%s 133MHz", comma ? "," : "");
157                 comma = 1;
158         }
159         if (status & PCIXM_STATUS_266CAP) {
160                 printf("%s 266MHz", comma ? "," : "");
161                 comma = 1;
162         }
163         if (status & PCIXM_STATUS_533CAP) {
164                 printf("%s 533MHz", comma ? "," : "");
165                 comma = 1;
166         }
167         if ((p->pc_hdr & PCIM_HDRTYPE) == 1)
168                 return;
169         switch (status & PCIXM_STATUS_MAX_READ) {
170         case PCIXM_STATUS_MAX_READ_512:
171                 max_burst_read = 512;
172                 break;
173         case PCIXM_STATUS_MAX_READ_1024:
174                 max_burst_read = 1024;
175                 break;
176         case PCIXM_STATUS_MAX_READ_2048:
177                 max_burst_read = 2048;
178                 break;
179         case PCIXM_STATUS_MAX_READ_4096:
180                 max_burst_read = 4096;
181                 break;
182         }
183         switch (status & PCIXM_STATUS_MAX_SPLITS) {
184         case PCIXM_STATUS_MAX_SPLITS_1:
185                 max_splits = 1;
186                 break;
187         case PCIXM_STATUS_MAX_SPLITS_2:
188                 max_splits = 2;
189                 break;
190         case PCIXM_STATUS_MAX_SPLITS_3:
191                 max_splits = 3;
192                 break;
193         case PCIXM_STATUS_MAX_SPLITS_4:
194                 max_splits = 4;
195                 break;
196         case PCIXM_STATUS_MAX_SPLITS_8:
197                 max_splits = 8;
198                 break;
199         case PCIXM_STATUS_MAX_SPLITS_12:
200                 max_splits = 12;
201                 break;
202         case PCIXM_STATUS_MAX_SPLITS_16:
203                 max_splits = 16;
204                 break;
205         case PCIXM_STATUS_MAX_SPLITS_32:
206                 max_splits = 32;
207                 break;
208         }
209         printf("%s %d burst read, %d split transaction%s", comma ? "," : "",
210             max_burst_read, max_splits, max_splits == 1 ? "" : "s");
211 }
212
213 static void
214 cap_ht(int fd, struct pci_conf *p, uint8_t ptr)
215 {
216         uint32_t reg;
217         uint16_t command;
218
219         command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2);
220         printf("HT ");
221         if ((command & 0xe000) == PCIM_HTCAP_SLAVE)
222                 printf("slave");
223         else if ((command & 0xe000) == PCIM_HTCAP_HOST)
224                 printf("host");
225         else
226                 switch (command & PCIM_HTCMD_CAP_MASK) {
227                 case PCIM_HTCAP_SWITCH:
228                         printf("switch");
229                         break;
230                 case PCIM_HTCAP_INTERRUPT:
231                         printf("interrupt");
232                         break;
233                 case PCIM_HTCAP_REVISION_ID:
234                         printf("revision ID");
235                         break;
236                 case PCIM_HTCAP_UNITID_CLUMPING:
237                         printf("unit ID clumping");
238                         break;
239                 case PCIM_HTCAP_EXT_CONFIG_SPACE:
240                         printf("extended config space");
241                         break;
242                 case PCIM_HTCAP_ADDRESS_MAPPING:
243                         printf("address mapping");
244                         break;
245                 case PCIM_HTCAP_MSI_MAPPING:
246                         printf("MSI %saddress window %s at 0x",
247                             command & PCIM_HTCMD_MSI_FIXED ? "fixed " : "",
248                             command & PCIM_HTCMD_MSI_ENABLE ? "enabled" :
249                             "disabled");
250                         if (command & PCIM_HTCMD_MSI_FIXED)
251                                 printf("fee00000");
252                         else {
253                                 reg = read_config(fd, &p->pc_sel,
254                                     ptr + PCIR_HTMSI_ADDRESS_HI, 4);
255                                 if (reg != 0)
256                                         printf("%08x", reg);
257                                 reg = read_config(fd, &p->pc_sel,
258                                     ptr + PCIR_HTMSI_ADDRESS_LO, 4);
259                                 printf("%08x", reg);
260                         }
261                         break;
262                 case PCIM_HTCAP_DIRECT_ROUTE:
263                         printf("direct route");
264                         break;
265                 case PCIM_HTCAP_VCSET:
266                         printf("VC set");
267                         break;
268                 case PCIM_HTCAP_RETRY_MODE:
269                         printf("retry mode");
270                         break;
271                 default:
272                         printf("unknown %02x", command);
273                         break;
274                 }
275 }
276
277 static void
278 cap_vendor(int fd, struct pci_conf *p, uint8_t ptr)
279 {
280         uint8_t length;
281
282         length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1);
283         printf("vendor (length %d)", length);
284         if (p->pc_vendor == 0x8086) {
285                 /* Intel */
286                 uint8_t version;
287
288                 version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA,
289                     1);
290                 printf(" Intel cap %d version %d", version >> 4, version & 0xf);
291                 if (version >> 4 == 1 && length == 12) {
292                         /* Feature Detection */
293                         uint32_t fvec;
294                         int comma;
295
296                         comma = 0;
297                         fvec = read_config(fd, &p->pc_sel, ptr +
298                             PCIR_VENDOR_DATA + 5, 4);
299                         printf("\n\t\t features:");
300                         if (fvec & (1 << 0)) {
301                                 printf(" AMT");
302                                 comma = 1;
303                         }
304                         fvec = read_config(fd, &p->pc_sel, ptr +
305                             PCIR_VENDOR_DATA + 1, 4);
306                         if (fvec & (1 << 21)) {
307                                 printf("%s Quick Resume", comma ? "," : "");
308                                 comma = 1;
309                         }
310                         if (fvec & (1 << 18)) {
311                                 printf("%s SATA RAID-5", comma ? "," : "");
312                                 comma = 1;
313                         }
314                         if (fvec & (1 << 9)) {
315                                 printf("%s Mobile", comma ? "," : "");
316                                 comma = 1;
317                         }
318                         if (fvec & (1 << 7)) {
319                                 printf("%s 6 PCI-e x1 slots", comma ? "," : "");
320                                 comma = 1;
321                         } else {
322                                 printf("%s 4 PCI-e x1 slots", comma ? "," : "");
323                                 comma = 1;
324                         }
325                         if (fvec & (1 << 5)) {
326                                 printf("%s SATA RAID-0/1/10", comma ? "," : "");
327                                 comma = 1;
328                         }
329                         if (fvec & (1 << 3)) {
330                                 printf("%s SATA AHCI", comma ? "," : "");
331                                 comma = 1;
332                         }
333                 }
334         }
335 }
336
337 static void
338 cap_debug(int fd, struct pci_conf *p, uint8_t ptr)
339 {
340         uint16_t debug_port;
341
342         debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2);
343         printf("EHCI Debug Port at offset 0x%x in map 0x%x", debug_port &
344             PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13));
345 }
346
347 static void
348 cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr)
349 {
350         uint32_t id;
351
352         id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4);
353         printf("PCI Bridge card=0x%08x", id);
354 }
355
356 static void
357 cap_express(int fd, struct pci_conf *p, uint8_t ptr)
358 {
359         uint16_t flags;
360
361         flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2);
362         printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION);
363         switch (flags & PCIM_EXP_FLAGS_TYPE) {
364         case PCIM_EXP_TYPE_ENDPOINT:
365                 printf("endpoint");
366                 break;
367         case PCIM_EXP_TYPE_LEGACY_ENDPOINT:
368                 printf("legacy endpoint");
369                 break;
370         case PCIM_EXP_TYPE_ROOT_PORT:
371                 printf("root port");
372                 break;
373         case PCIM_EXP_TYPE_UPSTREAM_PORT:
374                 printf("upstream port");
375                 break;
376         case PCIM_EXP_TYPE_DOWNSTREAM_PORT:
377                 printf("downstream port");
378                 break;
379         case PCIM_EXP_TYPE_PCI_BRIDGE:
380                 printf("PCI bridge");
381                 break;
382         default:
383                 printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8);
384                 break;
385         }
386         if (flags & PCIM_EXP_FLAGS_IRQ)
387                 printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 17);
388 }
389
390 static void
391 cap_msix(int fd, struct pci_conf *p, uint8_t ptr)
392 {
393         uint32_t val;
394         uint16_t ctrl;
395         int msgnum, table_bar, pba_bar;
396
397         ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2);
398         msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1;
399         val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4);
400         table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);
401         val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4);
402         pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK);   
403         printf("MSI-X supports %d message%s ", msgnum,
404             (msgnum == 1) ? "" : "s");
405         if (table_bar == pba_bar)
406                 printf("in map 0x%x", table_bar);
407         else
408                 printf("in maps 0x%x and 0x%x", table_bar, pba_bar);
409         if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE)
410                 printf(" enabled");
411 }
412
413 void
414 list_caps(int fd, struct pci_conf *p)
415 {
416         uint16_t cmd;
417         uint8_t ptr, cap;
418
419         /* Are capabilities present for this device? */
420         cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2);
421         if (!(cmd & PCIM_STATUS_CAPPRESENT))
422                 return;
423
424         switch (p->pc_hdr & PCIM_HDRTYPE) {
425         case 0:
426         case 1:
427                 ptr = PCIR_CAP_PTR;
428                 break;
429         case 2:
430                 ptr = PCIR_CAP_PTR_2;
431                 break;
432         default:
433                 errx(1, "list_caps: bad header type");
434         }
435
436         /* Walk the capability list. */
437         ptr = read_config(fd, &p->pc_sel, ptr, 1);
438         while (ptr != 0 && ptr != 0xff) {
439                 cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1);
440                 printf("    cap %02x[%02x] = ", cap, ptr);
441                 switch (cap) {
442                 case PCIY_PMG:
443                         cap_power(fd, p, ptr);
444                         break;
445                 case PCIY_AGP:
446                         cap_agp(fd, p, ptr);
447                         break;
448                 case PCIY_VPD:
449                         cap_vpd(fd, p, ptr);
450                         break;
451                 case PCIY_MSI:
452                         cap_msi(fd, p, ptr);
453                         break;
454                 case PCIY_PCIX:
455                         cap_pcix(fd, p, ptr);
456                         break;
457                 case PCIY_HT:
458                         cap_ht(fd, p, ptr);
459                         break;
460                 case PCIY_VENDOR:
461                         cap_vendor(fd, p, ptr);
462                         break;
463                 case PCIY_DEBUG:
464                         cap_debug(fd, p, ptr);
465                         break;
466                 case PCIY_SUBVENDOR:
467                         cap_subvendor(fd, p, ptr);
468                         break;
469                 case PCIY_EXPRESS:
470                         cap_express(fd, p, ptr);
471                         break;
472                 case PCIY_MSIX:
473                         cap_msix(fd, p, ptr);
474                         break;
475                 default:
476                         printf("unknown");
477                         break;
478                 }
479                 printf("\n");
480                 ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1);
481         }
482 }