1 #ifndef CPUCounters_LSPCI_H
2 #define CPUCounters_LSPCI_H
3
4 #include <vector>
5 #include <fstream>
6 #include <memory>
7 #include "cpucounters.h"
8
9 #if defined(_MSC_VER)
10 #define PCI_IDS_PATH "pci.ids"
11 #define PCI_IDS_NOT_FOUND "pci.ids file is not available. Download it from" \
12 " https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids."
13 #elif defined (__FreeBSD__) || defined(__DragonFly__)
14 #define PCI_IDS_PATH "/usr/local/share/pciids/pci.ids"
15 #define PCI_IDS_NOT_FOUND "/usr/local/share/pciids/pci.ids file is not available." \
16 " Ensure that the \"pciids\" package is properly installed or download" \
17 " https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids and" \
18 " copy it to the current directory."
19 #else
20 #define PCI_IDS_PATH "/usr/share/hwdata/pci.ids"
21 #define PCI_IDS_NOT_FOUND "/usr/share/hwdata/pci.ids file is not available." \
22 " Ensure that the \"hwdata\" package is properly installed or download" \
23 " https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids and" \
24 " copy it to the current directory."
25 #endif
26
27 namespace pcm {
28
29 typedef uint32_t h_id;
30 typedef uint32_t v_id;
31 typedef std::map<std::pair<h_id,v_id>,uint64_t> ctr_data;
32 typedef std::vector<ctr_data> stack_content;
33 typedef std::vector<stack_content> result_content;
34
35 class ccr {
36 public:
37 virtual uint64_t get_event_select() const = 0;
38 virtual void set_event_select(uint64_t value) = 0;
39 virtual uint64_t get_umask() const = 0;
40 virtual void set_umask(uint64_t value) = 0;
41 virtual uint64_t get_reset() const = 0;
42 virtual void set_reset(uint64_t value) = 0;
43 virtual uint64_t get_edge() const = 0;
44 virtual void set_edge(uint64_t value) = 0;
45 virtual uint64_t get_ov_en() const = 0;
46 virtual void set_ov_en(uint64_t value) = 0;
47 virtual uint64_t get_enable() const = 0;
48 virtual void set_enable(uint64_t value) = 0;
49 virtual uint64_t get_invert() const = 0;
50 virtual void set_invert(uint64_t value) = 0;
51 virtual uint64_t get_thresh() const = 0;
52 virtual void set_thresh(uint64_t value) = 0;
53 virtual uint64_t get_ch_mask() const = 0;
54 virtual void set_ch_mask(uint64_t value) = 0;
55 virtual uint64_t get_fc_mask() const = 0;
56 virtual void set_fc_mask(uint64_t value) = 0;
57 virtual uint64_t get_ccr_value() const = 0;
58 virtual void set_ccr_value(uint64_t value) = 0;
~ccr()59 virtual ~ccr() {};
60 };
61
62 class skx_ccr: public ccr {
63 public:
skx_ccr(uint64_t & v)64 skx_ccr(uint64_t &v){
65 ccr_value = &v;
66 }
get_event_select()67 virtual uint64_t get_event_select() const {
68 return (*ccr_value & 0xFF);
69 }
set_event_select(uint64_t value)70 virtual void set_event_select(uint64_t value) {
71 *ccr_value |= value;
72 }
get_umask()73 virtual uint64_t get_umask() const {
74 return ((*ccr_value >> 8) & 0xFF);
75 }
set_umask(uint64_t value)76 virtual void set_umask(uint64_t value) {
77 *ccr_value |= (value << 8);
78 }
get_reset()79 virtual uint64_t get_reset() const {
80 return ((*ccr_value >> 17) & 0x01);
81 }
set_reset(uint64_t value)82 virtual void set_reset(uint64_t value) {
83 *ccr_value |= (value << 17);
84 }
get_edge()85 virtual uint64_t get_edge() const {
86 return ((*ccr_value >> 18) & 0x01);
87 }
set_edge(uint64_t value)88 virtual void set_edge(uint64_t value) {
89 *ccr_value |= (value << 18);
90 }
get_ov_en()91 virtual uint64_t get_ov_en() const {
92 return ((*ccr_value >> 20) & 0x01);
93 }
set_ov_en(uint64_t value)94 virtual void set_ov_en(uint64_t value) {
95 *ccr_value |= (value << 20);
96 }
get_enable()97 virtual uint64_t get_enable() const {
98 return ((*ccr_value >> 22) & 0x01);
99 }
set_enable(uint64_t value)100 virtual void set_enable(uint64_t value) {
101 *ccr_value |= (value << 22);
102 }
get_invert()103 virtual uint64_t get_invert() const {
104 return ((*ccr_value >> 23) & 0x01);
105 }
set_invert(uint64_t value)106 virtual void set_invert(uint64_t value) {
107 *ccr_value |= (value << 23);
108 }
get_thresh()109 virtual uint64_t get_thresh() const {
110 return ((*ccr_value >> 24) & 0xFFF);
111 }
set_thresh(uint64_t value)112 virtual void set_thresh(uint64_t value) {
113 *ccr_value |= (value << 24);
114 }
get_ch_mask()115 virtual uint64_t get_ch_mask() const {
116 return ((*ccr_value >> 36) & 0xFF);
117 }
set_ch_mask(uint64_t value)118 virtual void set_ch_mask(uint64_t value) {
119 *ccr_value |= (value << 36);
120 }
get_fc_mask()121 virtual uint64_t get_fc_mask() const {
122 return ((*ccr_value >> 44) & 0x07);
123 }
set_fc_mask(uint64_t value)124 virtual void set_fc_mask(uint64_t value) {
125 *ccr_value |= (value << 44);
126 }
get_ccr_value()127 virtual uint64_t get_ccr_value() const {
128 return *ccr_value;
129 }
set_ccr_value(uint64_t value)130 virtual void set_ccr_value(uint64_t value) {
131 *ccr_value = value;
132 }
133
134 private:
135 uint64_t* ccr_value = NULL;
136 };
137
138 class icx_ccr: public ccr {
139 public:
icx_ccr(uint64_t & v)140 icx_ccr(uint64_t &v){
141 ccr_value = &v;
142 }
get_event_select()143 virtual uint64_t get_event_select() const {
144 return (*ccr_value & 0xFF);
145 }
set_event_select(uint64_t value)146 virtual void set_event_select(uint64_t value) {
147 *ccr_value |= value;
148 }
get_umask()149 virtual uint64_t get_umask() const {
150 return ((*ccr_value >> 8) & 0xFF);
151 }
set_umask(uint64_t value)152 virtual void set_umask(uint64_t value) {
153 *ccr_value |= (value << 8);
154 }
get_reset()155 virtual uint64_t get_reset() const {
156 return ((*ccr_value >> 17) & 0x01);
157 }
set_reset(uint64_t value)158 virtual void set_reset(uint64_t value) {
159 *ccr_value |= (value << 17);
160 }
get_edge()161 virtual uint64_t get_edge() const {
162 return ((*ccr_value >> 18) & 0x01);
163 }
set_edge(uint64_t value)164 virtual void set_edge(uint64_t value) {
165 *ccr_value |= (value << 18);
166 }
get_ov_en()167 virtual uint64_t get_ov_en() const {
168 return ((*ccr_value >> 20) & 0x01);
169 }
set_ov_en(uint64_t value)170 virtual void set_ov_en(uint64_t value) {
171 *ccr_value |= (value << 20);
172 }
get_enable()173 virtual uint64_t get_enable() const {
174 return ((*ccr_value >> 22) & 0x01);
175 }
set_enable(uint64_t value)176 virtual void set_enable(uint64_t value) {
177 *ccr_value |= (value << 22);
178 }
get_invert()179 virtual uint64_t get_invert() const {
180 return ((*ccr_value >> 23) & 0x01);
181 }
set_invert(uint64_t value)182 virtual void set_invert(uint64_t value) {
183 *ccr_value |= (value << 23);
184 }
get_thresh()185 virtual uint64_t get_thresh() const {
186 return ((*ccr_value >> 24) & 0xFFF);
187 }
set_thresh(uint64_t value)188 virtual void set_thresh(uint64_t value) {
189 *ccr_value |= (value << 24);
190 }
get_ch_mask()191 virtual uint64_t get_ch_mask() const {
192 return ((*ccr_value >> 36) & 0xFFF);
193 }
set_ch_mask(uint64_t value)194 virtual void set_ch_mask(uint64_t value) {
195 *ccr_value |= (value << 36);
196 }
get_fc_mask()197 virtual uint64_t get_fc_mask() const {
198 return ((*ccr_value >> 48) & 0x07);
199 }
set_fc_mask(uint64_t value)200 virtual void set_fc_mask(uint64_t value) {
201 *ccr_value |= (value << 48);
202 }
get_ccr_value()203 virtual uint64_t get_ccr_value() const {
204 return *ccr_value;
205 }
set_ccr_value(uint64_t value)206 virtual void set_ccr_value(uint64_t value) {
207 *ccr_value = value;
208 }
209
210 private:
211 uint64_t* ccr_value = NULL;
212 };
213 struct bdf {
214 uint8_t busno;
215 uint8_t devno;
216 uint8_t funcno;
bdfbdf217 bdf () : busno(0), devno(0), funcno(0) {}
218 };
219
220 struct pci {
221 bool exist = false;
222 struct bdf bdf;
223 union {
224 struct {
225 uint16_t vendor_id;
226 uint16_t device_id;
227 };
228 uint32_t offset_0;
229 };
230 int8_t header_type;
231 union {
232 struct {
233 uint8_t primary_bus_number;
234 uint8_t secondary_bus_number;
235 uint8_t subordinate_bus_number;
236 uint8_t junk;
237 };
238 uint32_t offset_18;
239 };
240 union {
241 struct {
242 uint16_t link_ctrl;
243 union {
244 struct {
245 uint16_t link_speed : 4;
246 uint16_t link_width : 6;
247 uint16_t undefined : 1;
248 uint16_t link_trained : 1;
249 };
250 uint16_t link_sta;
251 };
252 };
253 uint32_t link_info;
254 };
pcipci255 pci () : exist(false), offset_0(0), header_type(0), offset_18(0), link_info(0) {}
256 };
257
258 struct counter {
259 std::string h_event_name;
260 std::string v_event_name;
261 uint64_t ccr;
262 int idx; /* Some counters need to be placed in specific index */
263 int multiplier;
264 int divider;
265 uint32_t h_id;
266 uint32_t v_id;
267 std::vector<result_content> data;
268 };
269
270 struct iio_skx {
271 struct {
272 struct {
273 struct pci root_pci_dev; /* single device represent root port */
274 std::vector<struct pci> child_pci_devs; /* Contain child switch and end-point devices */
275 } parts[4]; /* part 0, 1, 2, 3 */
276 uint8_t busno; /* holding busno for each IIO stack */
277 std::string stack_name;
278 std::vector<uint64_t> values;
279 bool flipped = false;
280 } stacks[6]; /* iio stack 0, 1, 2, 3, 4, 5 */
281 uint32_t socket_id;
282 };
283
284 struct iio_bifurcated_part {
285 int part_id;
286 /* single device represent root port */
287 struct pci root_pci_dev;
288 /* Contain child switch and end-point devices */
289 std::vector<struct pci> child_pci_devs;
290 };
291
292 struct iio_stack {
293 std::vector<struct iio_bifurcated_part> parts;
294 uint32_t iio_unit_id;
295 std::string stack_name;
296 std::vector<uint64_t> values;
297 bool flipped = false;
298 /* holding busno for each IIO stack */
299 uint8_t busno;
300 };
301
302 bool operator<(const iio_stack& lh, const iio_stack& rh)
303 {
304 return lh.iio_unit_id < rh.iio_unit_id;
305 }
306
307 struct iio_stacks_on_socket {
308 std::vector<struct iio_stack> stacks;
309 uint32_t socket_id;
310 };
311
312 bool operator < (const bdf &l, const bdf &r) {
313 if (l.busno < r.busno)
314 return true;
315 if (l.busno > r.busno)
316 return false;
317 if (l.devno < r.devno)
318 return true;
319 if (l.devno > r.devno)
320 return false;
321 if (l.funcno < r.funcno)
322 return true;
323 if (l.funcno > r.funcno)
324 return false;
325
326 return false; // bdf == bdf
327 };
328
probe_capability_pci_express(struct pci * p,uint32_t cap_ptr)329 void probe_capability_pci_express(struct pci *p, uint32_t cap_ptr)
330 {
331 struct cap {
332 union {
333 struct {
334 uint8_t id;
335 union {
336 uint8_t next;
337 uint8_t cap_ptr;
338 };
339 uint16_t junk;
340 };
341 uint32 dw0;
342 };
343 } cap;
344 uint32 value;
345 PciHandleType h(0, p->bdf.busno, p->bdf.devno, p->bdf.funcno);
346 h.read32(cap_ptr, &value); //Capability pointer
347 cap.dw0 = value;
348 if (cap.id != 0x10 && cap.next != 0x00) {
349 probe_capability_pci_express(p, cap.cap_ptr);
350 } else {
351 if (cap.id == 0x10) { // We're in PCI express capability structure
352 h.read32(cap_ptr+0x10, &value);
353 p->link_info = value;
354 } else { /*Finish recursive searching but cannot find PCI express capability structure*/ }
355 }
356 }
357
probe_pci(struct pci * p)358 bool probe_pci(struct pci *p)
359 {
360 uint32 value;
361 p->exist = false;
362 struct bdf *bdf = &p->bdf;
363 if (PciHandleType::exists(0, bdf->busno, bdf->devno, bdf->funcno)) {
364 PciHandleType h(0, bdf->busno, bdf->devno, bdf->funcno);
365 // VID:DID
366 h.read32(0x0, &value);
367 // Invalid VID::DID
368 if (value != (std::numeric_limits<unsigned int>::max)()) {
369 p->offset_0 = value;
370 h.read32(0xc, &value);
371 p->header_type = (value >> 16) & 0x7f;
372 if (p->header_type == 0) {
373 // Status register
374 h.read32(0x4, &value);
375 // Capability list == true
376 if (value & 0x100000) {
377 // Capability pointer
378 h.read32(0x34, &value);
379 probe_capability_pci_express(p, value);
380 }
381 } else if (p->header_type == 1) {
382 h.read32(0x18, &value);
383 p->offset_18 = value;
384 }
385 p->exist = true;
386 }
387 }
388
389 return p->exist;
390 }
391
392 /*
393 first : [vendorID] -> vencor name
394 second : [vendorID][deviceID] -> device name
395 */
396 typedef std::pair< std::map<int, std::string> ,std::map< int, std::map<int, std::string> > > PCIDB;
397
print_pci(struct pci p,const PCIDB & pciDB)398 void print_pci(struct pci p, const PCIDB & pciDB)
399 {
400 printf("Parent bridge info:");
401 printf("%x:%x.%d [%04x:%04x] %s %s %d P:%x S:%x S:%x ",
402 p.bdf.busno, p.bdf.devno, p.bdf.funcno,
403 p.vendor_id, p.device_id,
404 (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor",
405 (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device",
406 p.header_type,
407 p.primary_bus_number, p.secondary_bus_number, p.subordinate_bus_number);
408 printf("Device info:");
409 printf("%x:%x.%d [%04x:%04x] %s %s %d Gen%d x%d\n",
410 p.bdf.busno, p.bdf.devno, p.bdf.funcno,
411 p.vendor_id, p.device_id,
412 (pciDB.first.count(p.vendor_id) > 0)?pciDB.first.at(p.vendor_id).c_str():"unknown vendor",
413 (pciDB.second.count(p.vendor_id) > 0 && pciDB.second.at(p.vendor_id).count(p.device_id) > 0)?pciDB.second.at(p.vendor_id).at(p.device_id).c_str():"unknown device",
414 p.header_type,
415 p.link_speed, p.link_width);
416 }
417
load_PCIDB(PCIDB & pciDB)418 void load_PCIDB(PCIDB & pciDB)
419 {
420 std::ifstream in(PCI_IDS_PATH);
421 std::string line, item;
422
423 if (!in.is_open())
424 {
425 #ifndef _MSC_VER
426 // On Unix, try the current directory if the default path failed
427 in.open("pci.ids");
428 }
429
430 if (!in.is_open())
431 {
432 #endif
433 std::cerr << PCI_IDS_NOT_FOUND << "\n";
434 return;
435 }
436
437 int vendorID = -1;
438
439 while (std::getline(in, line)) {
440 // Ignore any line starting with #
441 if (line.size() == 0 || line[0] == '#')
442 continue;
443
444 if (line[0] == '\t' && line[1] == '\t')
445 {
446 // subvendor subdevice subsystem_name
447 continue;
448 }
449 if (line[0] == '\t')
450 {
451 int deviceID = stoi(line.substr(1,4),0,16);
452 //std::cout << vendorID << ";" << vendorName << ";" << deviceID << ";" << line.substr(7) << "\n";
453 pciDB.second[vendorID][deviceID] = line.substr(7);
454 continue;
455 }
456 // vendor
457 vendorID = stoi(line.substr(0,4),0,16);
458 pciDB.first[vendorID] = line.substr(6);
459 }
460 }
461
462 } // namespace pcm
463
464 #endif
465