Merge tag 'v3.10.86' into linux-linaro-lsk-v3.10
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / CCNDriver.cpp
1 /**
2  * Copyright (C) ARM Limited 2014-2015. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include "CCNDriver.h"
10
11 #include <unistd.h>
12 #include <sys/syscall.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16
17 #include "k/perf_event.h"
18
19 #include "Config.h"
20 #include "DriverSource.h"
21 #include "Logging.h"
22
23 static const char TAG_CATEGORY[] = "category";
24 static const char TAG_COUNTER_SET[] = "counter_set";
25 static const char TAG_EVENT[] = "event";
26 static const char TAG_OPTION[] = "option";
27 static const char TAG_OPTION_SET[] = "option_set";
28
29 static const char ATTR_AVERAGE_SELECTION[] = "average_selection";
30 static const char ATTR_COUNTER[] = "counter";
31 static const char ATTR_COUNT[] = "count";
32 static const char ATTR_DESCRIPTION[] = "description";
33 static const char ATTR_DISPLAY[] = "display";
34 static const char ATTR_EVENT[] = "event";
35 static const char ATTR_EVENT_DELTA[] = "event_delta";
36 static const char ATTR_NAME[] = "name";
37 static const char ATTR_OPTION_SET[] = "option_set";
38 static const char ATTR_TITLE[] = "title";
39 static const char ATTR_UNITS[] = "units";
40
41 static const char XP_REGION[] = "XP_Region";
42 static const char HNF_REGION[] = "HN-F_Region";
43 static const char RNI_REGION[] = "RN-I_Region";
44 static const char SBAS_REGION[] = "SBAS_Region";
45 static const char CCN_5XX[] = "CCN-5xx";
46 #define ARM_CCN_5XX "ARM_CCN_5XX_"
47
48 static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
49 static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
50 static const char *const XP_EVENT_DESCRIPTIONS[] = { NULL, "Set H-bit, signaled when this XP sets the H-bit.", "Set S-bit, signaled when this XP sets the S-bit.", "Set P-Cnt, signaled when this XP sets the P-Cnt. This is not applicable for the SNP VC.", "No TknV, signaled when this XP transmits a valid packet." };
51 static const char *const HNF_EVENT_NAMES[] = { NULL, "Cache Miss", "L3 SF Cache Access", "Cache Fill", "POCQ Retry", "POCQ Reqs Recvd", "SF Hit", "SF Evictions", "Snoops Sent", "Snoops Broadcast", "L3 Eviction", "L3 Fill Invalid Way", "MC Retries", "MC Reqs", "QOS HH Retry" };
52 static const char *const HNF_EVENT_DESCRIPTIONS[] = { NULL, "Counts the total cache misses. This is the first time lookup result, and is high priority.", "Counts the number of cache accesses. This is the first time access, and is high priority.", "Counts the total allocations in the HN L3 cache, and all cache line allocations to the L3 cache.", "Counts the number of requests that have been retried.", "Counts the number of requests received by HN.", "Counts the number of snoop filter hits.", "Counts the number of snoop filter evictions. Cache invalidations are initiated.", "Counts the number of snoops sent. Does not differentiate between broadcast or directed snoops.", "Counts the number of snoop broadcasts sent.", "Counts the number of L3 evictions.", "Counts the number of L3 fills to an invalid way.", "Counts the number of transactions retried by the memory controller.", "Counts the number of requests to the memory controller.", "Counts the number of times a highest-priority QoS class was retried at the HN-F." };
53 static const char *const RNI_EVENT_NAMES[] = { NULL, "S0 RDataBeats", "S1 RDataBeats", "S2 RDataBeats", "RXDAT Flits received", "TXDAT Flits sent", "Total TXREQ Flits sent", "Retried TXREQ Flits sent", "RRT full", "WRT full", "Replayed TXREQ Flits" };
54 static const char *const RNI_EVENT_DESCRIPTIONS[] = { NULL, "S0 RDataBeats.", "S1 RDataBeats.", "S2 RDataBeats.", "RXDAT Flits received.", "TXDAT Flits sent.", "Total TXREQ Flits sent.", "Retried TXREQ Flits sent.", "RRT full.", "WRT full.", "Replayed TXREQ Flits." };
55 static const char *const SBAS_EVENT_NAMES[] = { NULL, "S0 RDataBeats", NULL, NULL, "RXDAT Flits received", "TXDAT Flits sent", "Total TXREQ Flits sent", "Retried TXREQ Flits sent", "RRT full", "WRT full", "Replayed TXREQ Flits" };
56 static const char *const SBAS_EVENT_DESCRIPTIONS[] = { NULL, "S0 RDataBeats.", NULL, NULL, "RXDAT Flits received.", "TXDAT Flits sent.", "Total TXREQ Flits sent.", "Retried TXREQ Flits sent.", "RRT full.", "WRT full.", "Replayed TXREQ Flits." };
57
58 // This class is used only to poll for CCN-5xx configuration and emit events XML for it. All other operations are handled by PerfDriver
59
60 static int sys_perf_event_open(struct perf_event_attr *const attr, const pid_t pid, const int cpu, const int group_fd, const unsigned long flags) {
61         return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
62 }
63
64 static unsigned int getConfig(unsigned int node, unsigned int type, unsigned int event, unsigned int port, unsigned int vc) {
65   return
66     ((node  & 0xff) <<  0) |
67     ((type  & 0xff) <<  8) |
68     ((event & 0xff) << 16) |
69     ((port  & 0x03) << 24) |
70     ((vc    & 0x07) << 26) |
71     0;
72 }
73
74 static bool perfPoll(struct perf_event_attr *const pea) {
75         int fd = sys_perf_event_open(pea, -1, 0, -1, 0);
76         if (fd < 0) {
77                 return false;
78         }
79         close(fd);
80         return true;
81 }
82
83 CCNDriver::CCNDriver() : mNodeTypes(NULL), mXpCount(0) {
84 }
85
86 CCNDriver::~CCNDriver() {
87         delete mNodeTypes;
88 }
89
90 bool CCNDriver::claimCounter(const Counter &) const {
91         // Handled by PerfDriver
92         return false;
93 }
94
95 void CCNDriver::resetCounters() {
96         // Handled by PerfDriver
97 }
98
99 void CCNDriver::setupCounter(Counter &) {
100         // Handled by PerfDriver
101 }
102
103 void CCNDriver::readEvents(mxml_node_t *const) {
104         struct stat st;
105         if (stat("/sys/bus/event_source/devices/ccn", &st) != 0) {
106                 // Not found
107                 return;
108         }
109
110         int type;
111         if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
112                 logg->logError("Unable to read CCN-5xx type");
113                 handleException();
114         }
115
116         // Detect number of xps
117         struct perf_event_attr pea;
118         memset(&pea, 0, sizeof(pea));
119         pea.type = type;
120         pea.size = sizeof(pea);
121
122         mXpCount = 1;
123         while (true) {
124                 pea.config = getConfig(0, 0x08, 1, 0, 1) | mXpCount;
125                 if (!perfPoll(&pea)) {
126                         break;
127                 }
128                 mXpCount *= 2;
129         };
130         {
131                 int lower = mXpCount/2 + 1;
132                 while (lower < mXpCount) {
133                         int mid = (lower + mXpCount)/2;
134                         pea.config = getConfig(0, 0x08, 1, 0, 1) | mid;
135                         if (perfPoll(&pea)) {
136                                 lower = mid + 1;
137                         } else {
138                                 mXpCount = mid;
139                         }
140                 }
141         }
142
143         mNodeTypes = new NodeType[2*mXpCount];
144
145         // Detect node types
146         for (int i = 0; i < 2*mXpCount; ++i) {
147                 pea.config = getConfig(0, 0x04, 1, 0, 0) | i;
148                 if (perfPoll(&pea)) {
149                         mNodeTypes[i] = NT_HNF;
150                         continue;
151                 }
152
153                 pea.config = getConfig(0, 0x16, 1, 0, 0) | i;
154                 if (perfPoll(&pea)) {
155                         mNodeTypes[i] = NT_RNI;
156                         continue;
157                 }
158
159                 pea.config = getConfig(0, 0x10, 1, 0, 0) | i;
160                 if (perfPoll(&pea)) {
161                         mNodeTypes[i] = NT_SBAS;
162                         continue;
163                 }
164
165                 mNodeTypes[i] = NT_UNKNOWN;
166         }
167 }
168
169 int CCNDriver::writeCounters(mxml_node_t *const) const {
170         // Handled by PerfDriver
171         return 0;
172 }
173
174 void CCNDriver::writeEvents(mxml_node_t *const root) const {
175         mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
176         mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
177         mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
178
179         mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
180         mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
181         mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
182
183         mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
184         mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
185         mxmlElementSetAttr(clock_event, ATTR_EVENT, "0xff00");
186         mxmlElementSetAttr(clock_event, ATTR_TITLE, "CCN-5xx Clock");
187         mxmlElementSetAttr(clock_event, ATTR_NAME, "Cycles");
188         mxmlElementSetAttr(clock_event, ATTR_DISPLAY, "hertz");
189         mxmlElementSetAttr(clock_event, ATTR_UNITS, "Hz");
190         mxmlElementSetAttr(clock_event, ATTR_AVERAGE_SELECTION, "yes");
191         mxmlElementSetAttr(clock_event, ATTR_DESCRIPTION, "The number of core clock cycles");
192
193         mxml_node_t *const xp_option_set = mxmlNewElement(category, TAG_OPTION_SET);
194         mxmlElementSetAttr(xp_option_set, ATTR_NAME, XP_REGION);
195
196         for (int i = 0; i < mXpCount; ++i) {
197                 mxml_node_t *const option = mxmlNewElement(xp_option_set, TAG_OPTION);
198                 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
199                 mxmlElementSetAttrf(option, ATTR_NAME, "XP %i", i);
200                 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Crosspoint %i", i);
201         }
202
203         for (int vc = 0; vc < ARRAY_LENGTH(VC_TYPES); ++vc) {
204                 if (VC_TYPES[vc] == NULL) {
205                         continue;
206                 }
207                 for (int bus = 0; bus < 2; ++bus) {
208                         for (int eventId = 0; eventId < ARRAY_LENGTH(XP_EVENT_NAMES); ++eventId) {
209                                 if (XP_EVENT_NAMES[eventId] == NULL) {
210                                         continue;
211                                 }
212                                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
213                                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x08, eventId, bus, vc));
214                                 mxmlElementSetAttr(event, ATTR_OPTION_SET, XP_REGION);
215                                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
216                                 mxmlElementSetAttrf(event, ATTR_NAME, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_NAMES[eventId]);
217                                 mxmlElementSetAttrf(event, ATTR_DESCRIPTION, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_DESCRIPTIONS[eventId]);
218                         }
219                 }
220         }
221
222         mxml_node_t *const hnf_option_set = mxmlNewElement(category, TAG_OPTION_SET);
223         mxmlElementSetAttr(hnf_option_set, ATTR_NAME, HNF_REGION);
224
225         for (int eventId = 0; eventId < ARRAY_LENGTH(HNF_EVENT_NAMES); ++eventId) {
226                 if (HNF_EVENT_NAMES[eventId] == NULL) {
227                         continue;
228                 }
229                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
230                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x04, eventId, 0, 0));
231                 mxmlElementSetAttr(event, ATTR_OPTION_SET, HNF_REGION);
232                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
233                 mxmlElementSetAttr(event, ATTR_NAME, HNF_EVENT_NAMES[eventId]);
234                 mxmlElementSetAttr(event, ATTR_DESCRIPTION, HNF_EVENT_DESCRIPTIONS[eventId]);
235         }
236
237         mxml_node_t *const rni_option_set = mxmlNewElement(category, TAG_OPTION_SET);
238         mxmlElementSetAttr(rni_option_set, ATTR_NAME, RNI_REGION);
239
240         for (int eventId = 0; eventId < ARRAY_LENGTH(RNI_EVENT_NAMES); ++eventId) {
241                 if (RNI_EVENT_NAMES[eventId] == NULL) {
242                         continue;
243                 }
244                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
245                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x16, eventId, 0, 0));
246                 mxmlElementSetAttr(event, ATTR_OPTION_SET, RNI_REGION);
247                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
248                 mxmlElementSetAttr(event, ATTR_NAME, RNI_EVENT_NAMES[eventId]);
249                 mxmlElementSetAttr(event, ATTR_DESCRIPTION, RNI_EVENT_DESCRIPTIONS[eventId]);
250         }
251
252         mxml_node_t *const sbas_option_set = mxmlNewElement(category, TAG_OPTION_SET);
253         mxmlElementSetAttr(sbas_option_set, ATTR_NAME, SBAS_REGION);
254
255         for (int eventId = 0; eventId < ARRAY_LENGTH(SBAS_EVENT_NAMES); ++eventId) {
256                 if (SBAS_EVENT_NAMES[eventId] == NULL) {
257                         continue;
258                 }
259                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
260                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x10, eventId, 0, 0));
261                 mxmlElementSetAttr(event, ATTR_OPTION_SET, SBAS_REGION);
262                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
263                 mxmlElementSetAttr(event, ATTR_NAME, SBAS_EVENT_NAMES[eventId]);
264                 mxmlElementSetAttr(event, ATTR_DESCRIPTION, SBAS_EVENT_DESCRIPTIONS[eventId]);
265         }
266
267         for (int i = 0; i < 2*mXpCount; ++i) {
268                 switch (mNodeTypes[i]) {
269                 case NT_HNF: {
270                         mxml_node_t *const option = mxmlNewElement(hnf_option_set, TAG_OPTION);
271                         mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
272                         mxmlElementSetAttrf(option, ATTR_NAME, "HN-F %i", i);
273                         mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Fully-coherent Home Node %i", i);
274                         break;
275                 }
276                 case NT_RNI: {
277                         mxml_node_t *const option = mxmlNewElement(rni_option_set, TAG_OPTION);
278                         mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
279                         mxmlElementSetAttrf(option, ATTR_NAME, "RN-I %i", i);
280                         mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "I/O-coherent Requesting Node %i", i);
281                         break;
282                 }
283                 case NT_SBAS: {
284                         mxml_node_t *const option = mxmlNewElement(sbas_option_set, TAG_OPTION);
285                         mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
286                         mxmlElementSetAttrf(option, ATTR_NAME, "SBAS %i", i);
287                         mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "ACE master to CHI protocol bridge %i", i);
288                         break;
289                 }
290                 default:
291                         continue;
292                 }
293         }
294 }