17ff8a323SGerd Hoffmann /*
27ff8a323SGerd Hoffmann * The PCI Utilities -- Show Vendor-specific Capabilities
37ff8a323SGerd Hoffmann *
47ff8a323SGerd Hoffmann * Copyright (c) 2014 Gerd Hoffmann <[email protected]>
57ff8a323SGerd Hoffmann *
661829219SMartin Mares * Can be freely distributed and used under the terms of the GNU GPL v2+.
761829219SMartin Mares *
861829219SMartin Mares * SPDX-License-Identifier: GPL-2.0-or-later
97ff8a323SGerd Hoffmann */
107ff8a323SGerd Hoffmann
117ff8a323SGerd Hoffmann #include <stdio.h>
127ff8a323SGerd Hoffmann #include <string.h>
137ff8a323SGerd Hoffmann
147ff8a323SGerd Hoffmann #include "lspci.h"
157ff8a323SGerd Hoffmann
166ebebbaaSMartin Mares static int
show_vendor_caps_virtio(struct device * d,int where,int cap)177ff8a323SGerd Hoffmann show_vendor_caps_virtio(struct device *d, int where, int cap)
187ff8a323SGerd Hoffmann {
197ff8a323SGerd Hoffmann int length = BITS(cap, 0, 8);
207ff8a323SGerd Hoffmann int type = BITS(cap, 8, 8);
217ff8a323SGerd Hoffmann char *tname;
221bfc2be0SChangyuan Lyu u32 offset;
231bfc2be0SChangyuan Lyu u32 size;
241bfc2be0SChangyuan Lyu u32 offset_hi;
251bfc2be0SChangyuan Lyu u32 size_hi;
267ff8a323SGerd Hoffmann
277ff8a323SGerd Hoffmann if (length < 16)
286ebebbaaSMartin Mares return 0;
297ff8a323SGerd Hoffmann if (!config_fetch(d, where, length))
306ebebbaaSMartin Mares return 0;
317ff8a323SGerd Hoffmann
327ff8a323SGerd Hoffmann switch (type)
337ff8a323SGerd Hoffmann {
347ff8a323SGerd Hoffmann case 1:
357ff8a323SGerd Hoffmann tname = "CommonCfg";
367ff8a323SGerd Hoffmann break;
377ff8a323SGerd Hoffmann case 2:
387ff8a323SGerd Hoffmann tname = "Notify";
397ff8a323SGerd Hoffmann break;
407ff8a323SGerd Hoffmann case 3:
417ff8a323SGerd Hoffmann tname = "ISR";
427ff8a323SGerd Hoffmann break;
437ff8a323SGerd Hoffmann case 4:
447ff8a323SGerd Hoffmann tname = "DeviceCfg";
457ff8a323SGerd Hoffmann break;
461bfc2be0SChangyuan Lyu case 8:
471bfc2be0SChangyuan Lyu tname = "SharedMemory";
481bfc2be0SChangyuan Lyu break;
497ff8a323SGerd Hoffmann default:
507ff8a323SGerd Hoffmann tname = "<unknown>";
517ff8a323SGerd Hoffmann break;
527ff8a323SGerd Hoffmann }
537ff8a323SGerd Hoffmann
547ff8a323SGerd Hoffmann printf("VirtIO: %s\n", tname);
557ff8a323SGerd Hoffmann
567ff8a323SGerd Hoffmann if (verbose < 2)
576ebebbaaSMartin Mares return 1;
587ff8a323SGerd Hoffmann
591bfc2be0SChangyuan Lyu offset = get_conf_long(d, where + 8);
601bfc2be0SChangyuan Lyu size = get_conf_long(d, where + 12);
611bfc2be0SChangyuan Lyu if (type != 8)
626ebebbaaSMartin Mares printf("\t\tBAR=%d offset=%08x size=%08x",
631bfc2be0SChangyuan Lyu get_conf_byte(d, where + 4), offset, size);
641bfc2be0SChangyuan Lyu else {
651bfc2be0SChangyuan Lyu offset_hi = get_conf_long(d, where + 16);
661bfc2be0SChangyuan Lyu size_hi = get_conf_long(d, where + 20);
67*b78c087bSMartin Mares printf("\t\tBAR=%d offset=%016" PCI_U64_FMT_X " size=%016" PCI_U64_FMT_X " id=%d",
687ff8a323SGerd Hoffmann get_conf_byte(d, where + 4),
691bfc2be0SChangyuan Lyu (u64) offset | (u64) offset_hi << 32,
701bfc2be0SChangyuan Lyu (u64) size | (u64) size_hi << 32,
711bfc2be0SChangyuan Lyu get_conf_byte(d, where + 5));
721bfc2be0SChangyuan Lyu }
737ff8a323SGerd Hoffmann
746ebebbaaSMartin Mares if (type == 2 && length >= 20)
756ebebbaaSMartin Mares printf(" multiplier=%08x", get_conf_long(d, where+16));
767ff8a323SGerd Hoffmann
776ebebbaaSMartin Mares printf("\n");
786ebebbaaSMartin Mares return 1;
797ff8a323SGerd Hoffmann }
807ff8a323SGerd Hoffmann
816ebebbaaSMartin Mares static int
show_vendor_caps_intel(struct device * d,int where,int cap)82faa79db9SPali Rohár show_vendor_caps_intel(struct device *d, int where, int cap)
83faa79db9SPali Rohár {
84faa79db9SPali Rohár int length = BITS(cap, 0, 8);
85faa79db9SPali Rohár int version = BITS(cap, 8, 4);
86faa79db9SPali Rohár int type = BITS(cap, 12, 4);
87faa79db9SPali Rohár u32 l;
88faa79db9SPali Rohár
89faa79db9SPali Rohár if (type == 0)
90faa79db9SPali Rohár {
91faa79db9SPali Rohár printf("Intel Capabilities v%d\n", version);
92faa79db9SPali Rohár /*
93faa79db9SPali Rohár * Intel Capabilities is used at least on Intel Host Bridge / DRAM Controller
94faa79db9SPali Rohár * and Intel Integrated Graphics Controller. Format of the CAPID0_<X>
95faa79db9SPali Rohár * registers parsed below matches Cap Version 1 which is used since second
96faa79db9SPali Rohár * generation of the Intel Core processors (Sandy Bridge). Parsing of other
97faa79db9SPali Rohár * versions is not currently supported.
98faa79db9SPali Rohár */
99faa79db9SPali Rohár if (version != 1)
100faa79db9SPali Rohár return 1;
101faa79db9SPali Rohár }
102faa79db9SPali Rohár else if (type == 1)
103faa79db9SPali Rohár {
104faa79db9SPali Rohár printf("Intel Feature Detection\n");
105faa79db9SPali Rohár /*
106faa79db9SPali Rohár * Intel Feature Detection Capabilities is used on Intel LPC Controller.
107faa79db9SPali Rohár * Capabilities are accessed indirectly by writing indirect capability
108faa79db9SPali Rohár * register to PCI config space. Because lspci cannot write to PCI config
109faa79db9SPali Rohár * space, it is not possible to read or parse Intel Feature Vector Space.
110faa79db9SPali Rohár */
111faa79db9SPali Rohár return 1;
112faa79db9SPali Rohár }
113faa79db9SPali Rohár else
114faa79db9SPali Rohár {
115faa79db9SPali Rohár printf("Intel <unknown>\n");
116faa79db9SPali Rohár return 1;
117faa79db9SPali Rohár }
118faa79db9SPali Rohár
119faa79db9SPali Rohár if (!config_fetch(d, where, length))
120faa79db9SPali Rohár return 0;
121faa79db9SPali Rohár
122faa79db9SPali Rohár /* CAPID0_A */
123faa79db9SPali Rohár if (length >= 8)
124faa79db9SPali Rohár {
125faa79db9SPali Rohár l = get_conf_long(d, where + 4);
126faa79db9SPali Rohár printf("\t\tCapA:");
127faa79db9SPali Rohár printf(" Peg60Dis%c", FLAG(l, BIT(31)));
128faa79db9SPali Rohár printf(" Peg12Dis%c", FLAG(l, BIT(30)));
129faa79db9SPali Rohár printf(" Peg11Dis%c", FLAG(l, BIT(29)));
130faa79db9SPali Rohár printf(" Peg10Dis%c", FLAG(l, BIT(28)));
131faa79db9SPali Rohár printf(" PeLWUDis%c", FLAG(l, BIT(27)));
132faa79db9SPali Rohár printf(" DmiWidth=x%u", (l & BIT(26)) ? 2 : 4);
133faa79db9SPali Rohár printf("\n\t\t ");
134faa79db9SPali Rohár printf(" EccDis%c", FLAG(l, BIT(25)));
135faa79db9SPali Rohár printf(" ForceEccEn%c", FLAG(l, BIT(24)));
136faa79db9SPali Rohár printf(" VTdDis%c", FLAG(l, BIT(23)));
137faa79db9SPali Rohár printf(" DmiG2Dis%c", FLAG(l, BIT(22)));
138faa79db9SPali Rohár printf(" PegG2Dis%c", FLAG(l, BIT(21)));
139faa79db9SPali Rohár printf(" DDRMaxSize=");
140faa79db9SPali Rohár if (BITS(l, 19, 2) == 0)
141faa79db9SPali Rohár printf("Unlimited");
142faa79db9SPali Rohár else
143faa79db9SPali Rohár printf("%gGB/chan", 512 * (1 << ((3-BITS(l, 19, 2))*2)) / 1024.0);
144faa79db9SPali Rohár printf("\n\t\t ");
145faa79db9SPali Rohár printf(" 1NDis%c", FLAG(l, BIT(17)));
146faa79db9SPali Rohár printf(" CDDis%c", FLAG(l, BIT(15)));
147faa79db9SPali Rohár printf(" DDPCDis%c", FLAG(l, BIT(14)));
148faa79db9SPali Rohár printf(" X2APICEn%c", FLAG(l, BIT(13)));
149faa79db9SPali Rohár printf(" PDCDis%c", FLAG(l, BIT(12)));
150faa79db9SPali Rohár printf(" IGDis%c", FLAG(l, BIT(11)));
151faa79db9SPali Rohár printf(" CDID=%u", BITS(l, 8, 2));
152faa79db9SPali Rohár printf(" CRID=%u", BITS(l, 4, 4));
153faa79db9SPali Rohár printf("\n\t\t ");
154faa79db9SPali Rohár printf(" DDROCCAP%c", FLAG(l, BIT(3)));
155faa79db9SPali Rohár printf(" OCEn%c", FLAG(l, BIT(2)));
156faa79db9SPali Rohár printf(" DDRWrtVrefEn%c", FLAG(l, BIT(1)));
157faa79db9SPali Rohár printf(" DDR3LEn%c", FLAG(l, BIT(0)));
158faa79db9SPali Rohár printf("\n");
159faa79db9SPali Rohár }
160faa79db9SPali Rohár
161faa79db9SPali Rohár /* CAPID0_B */
162faa79db9SPali Rohár if (length >= 12)
163faa79db9SPali Rohár {
164faa79db9SPali Rohár l = get_conf_long(d, where + 8);
165faa79db9SPali Rohár printf("\t\tCapB:");
166faa79db9SPali Rohár printf(" ImguDis%c", FLAG(l, BIT(31)));
167faa79db9SPali Rohár printf(" OCbySSKUCap%c", FLAG(l, BIT(30)));
168faa79db9SPali Rohár printf(" OCbySSKUEn%c", FLAG(l, BIT(29)));
169faa79db9SPali Rohár printf(" SMTCap%c", FLAG(l, BIT(28)));
170faa79db9SPali Rohár printf(" CacheSzCap 0x%x", BITS(l, 25, 3));
171faa79db9SPali Rohár printf("\n\t\t ");
172faa79db9SPali Rohár printf(" SoftBinCap%c", FLAG(l, BIT(24)));
173faa79db9SPali Rohár printf(" DDR3MaxFreqWithRef100=");
174faa79db9SPali Rohár if (BITS(l, 21, 3) == 0)
175faa79db9SPali Rohár printf("Disabled");
176faa79db9SPali Rohár else if (BITS(l, 21, 3) == 7)
177faa79db9SPali Rohár printf("Unlimited");
178faa79db9SPali Rohár else
179faa79db9SPali Rohár printf("%uMHz", (6+BITS(l, 21, 3)) * 200);
180faa79db9SPali Rohár printf(" PegG3Dis%c", FLAG(l, BIT(20)));
181faa79db9SPali Rohár printf("\n\t\t ");
182faa79db9SPali Rohár printf(" PkgTyp%c", FLAG(l, BIT(19)));
183faa79db9SPali Rohár printf(" AddGfxEn%c", FLAG(l, BIT(18)));
184faa79db9SPali Rohár printf(" AddGfxCap%c", FLAG(l, BIT(17)));
185faa79db9SPali Rohár printf(" PegX16Dis%c", FLAG(l, BIT(16)));
186faa79db9SPali Rohár printf(" DmiG3Dis%c", FLAG(l, BIT(15)));
187faa79db9SPali Rohár printf(" GmmDis%c", FLAG(l, BIT(8)));
188faa79db9SPali Rohár printf("\n\t\t ");
189faa79db9SPali Rohár printf(" DDR3MaxFreq=%uMHz", (11-BITS(l, 4, 2)) * 2666 / 10);
190faa79db9SPali Rohár printf(" LPDDR3En%c", FLAG(l, BIT(2)));
191faa79db9SPali Rohár printf("\n");
192faa79db9SPali Rohár }
193faa79db9SPali Rohár
194faa79db9SPali Rohár /* CAPID0_C */
195faa79db9SPali Rohár if (length >= 16)
196faa79db9SPali Rohár {
197faa79db9SPali Rohár l = get_conf_long(d, where + 12);
198faa79db9SPali Rohár printf("\t\tCapC:");
199faa79db9SPali Rohár printf(" PegG4Dis%c", FLAG(l, BIT(28)));
200faa79db9SPali Rohár printf(" DDR4MaxFreq=");
201faa79db9SPali Rohár if (BITS(l, 23, 4) == 0)
202faa79db9SPali Rohár printf("Unlimited");
203faa79db9SPali Rohár else
204faa79db9SPali Rohár printf("%uMHz", BITS(l, 0, 4) * 2666 / 10);
205faa79db9SPali Rohár printf(" LPDDREn%c", FLAG(l, BIT(22)));
206faa79db9SPali Rohár printf(" LPDDR4MaxFreq=");
207faa79db9SPali Rohár if (BITS(l, 17, 4) == 0)
208faa79db9SPali Rohár printf("Unlimited");
209faa79db9SPali Rohár else
210faa79db9SPali Rohár printf("%uMHz", BITS(l, 0, 4) * 2666 / 10);
211faa79db9SPali Rohár printf(" LPDDR4En%c", FLAG(l, BIT(16)));
212faa79db9SPali Rohár printf("\n\t\t ");
213faa79db9SPali Rohár printf(" QClkGvDis%c", FLAG(l, BIT(14)));
214faa79db9SPali Rohár printf(" SgxDis%c", FLAG(l, BIT(9)));
215faa79db9SPali Rohár printf(" BClkOC=%s", BITS(l, 7, 2) == 0 ? "Disabled" :
216faa79db9SPali Rohár BITS(l, 7, 2) == 1 ? "115MHz" :
217faa79db9SPali Rohár BITS(l, 7, 2) == 2 ? "130MHz" :
218faa79db9SPali Rohár "Unlimited");
219faa79db9SPali Rohár printf(" IddDis%c", FLAG(l, BIT(6)));
220faa79db9SPali Rohár printf(" Pipe3Dis%c", FLAG(l, BIT(5)));
221faa79db9SPali Rohár printf(" Gear1MaxFreq=");
222faa79db9SPali Rohár if (BITS(l, 0, 4) == 0)
223faa79db9SPali Rohár printf("Unlimited");
224faa79db9SPali Rohár else
225faa79db9SPali Rohár printf("%uMHz", BITS(l, 0, 4) * 2666 / 10);
226faa79db9SPali Rohár printf("\n");
227faa79db9SPali Rohár }
228faa79db9SPali Rohár
229faa79db9SPali Rohár return 1;
230faa79db9SPali Rohár }
231faa79db9SPali Rohár
232faa79db9SPali Rohár static int
do_show_vendor_caps(struct device * d,int where,int cap)2336ebebbaaSMartin Mares do_show_vendor_caps(struct device *d, int where, int cap)
2347ff8a323SGerd Hoffmann {
235adf7de0eSDavid Edmondson switch (d->dev->vendor_id)
2367ff8a323SGerd Hoffmann {
2377ff8a323SGerd Hoffmann case 0x1af4: /* Red Hat */
238adf7de0eSDavid Edmondson if (d->dev->device_id >= 0x1000 &&
239adf7de0eSDavid Edmondson d->dev->device_id <= 0x107f)
2406ebebbaaSMartin Mares return show_vendor_caps_virtio(d, where, cap);
2417ff8a323SGerd Hoffmann break;
242faa79db9SPali Rohár case 0x8086: /* Intel */
243faa79db9SPali Rohár return show_vendor_caps_intel(d, where, cap);
2447ff8a323SGerd Hoffmann }
2456ebebbaaSMartin Mares return 0;
2466ebebbaaSMartin Mares }
2476ebebbaaSMartin Mares
2486ebebbaaSMartin Mares void
show_vendor_caps(struct device * d,int where,int cap)2496ebebbaaSMartin Mares show_vendor_caps(struct device *d, int where, int cap)
2506ebebbaaSMartin Mares {
2516ebebbaaSMartin Mares printf("Vendor Specific Information: ");
2526ebebbaaSMartin Mares if (!do_show_vendor_caps(d, where, cap))
2536ebebbaaSMartin Mares printf("Len=%02x <?>\n", BITS(cap, 0, 8));
2547ff8a323SGerd Hoffmann }
255