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