tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / tools / gator / daemon / CCNDriver.cpp
1 /**
2  * Copyright (C) ARM Limited 2014. 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_COUNTER_SET[] = "counter_set";
32 static const char ATTR_COUNT[] = "count";
33 static const char ATTR_DESCRIPTION[] = "description";
34 static const char ATTR_DISPLAY[] = "display";
35 static const char ATTR_EVENT[] = "event";
36 static const char ATTR_EVENT_DELTA[] = "event_delta";
37 static const char ATTR_NAME[] = "name";
38 static const char ATTR_OPTION_SET[] = "option_set";
39 static const char ATTR_TITLE[] = "title";
40 static const char ATTR_UNITS[] = "units";
41
42 static const char XP_REGION[] = "XP_Region";
43 static const char HNF_REGION[] = "HN-F_Region";
44 static const char RNI_REGION[] = "RN-I_Region";
45 static const char SBAS_REGION[] = "SBAS_Region";
46 static const char CCN_5XX[] = "CCN-5xx";
47 #define ARM_CCN_5XX "ARM_CCN_5XX_"
48
49 static const char *const VC_TYPES[] = { "REQ", "RSP", "SNP", "DAT" };
50 static const char *const XP_EVENT_NAMES[] = { NULL, "H-bit", "S-bit", "P-Cnt", "TknV" };
51 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." };
52 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" };
53 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." };
54 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" };
55 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." };
56 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" };
57 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." };
58
59 // This class is used only to poll for CCN-5xx configuration and emit events XML for it. All other operations are handled by PerfDriver
60
61 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) {
62         return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
63 }
64
65 static unsigned int getConfig(unsigned int node, unsigned int type, unsigned int event, unsigned int port, unsigned int vc) {
66   return
67     ((node  & 0xff) <<  0) |
68     ((type  & 0xff) <<  8) |
69     ((event & 0xff) << 16) |
70     ((port  & 0x03) << 24) |
71     ((vc    & 0x07) << 26) |
72     0;
73 }
74
75 static bool perfPoll(struct perf_event_attr *const pea) {
76         int fd = sys_perf_event_open(pea, -1, 0, -1, 0);
77         if (fd < 0) {
78                 return false;
79         }
80         close(fd);
81         return true;
82 }
83
84 CCNDriver::CCNDriver() : mNodeTypes(NULL), mXpCount(0) {
85 }
86
87 CCNDriver::~CCNDriver() {
88         delete mNodeTypes;
89 }
90
91 bool CCNDriver::claimCounter(const Counter &) const {
92         // Handled by PerfDriver
93         return false;
94 }
95
96 void CCNDriver::resetCounters() {
97         // Handled by PerfDriver
98 }
99
100 void CCNDriver::setupCounter(Counter &) {
101         // Handled by PerfDriver
102 }
103
104 void CCNDriver::readEvents(mxml_node_t *const) {
105         struct stat st;
106         if (stat("/sys/bus/event_source/devices/ccn", &st) != 0) {
107                 // Not found
108                 return;
109         }
110
111         int type;
112         if (DriverSource::readIntDriver("/sys/bus/event_source/devices/ccn/type", &type) != 0) {
113                 logg->logError(__FILE__, __LINE__, "Unable to read CCN-5xx type");
114                 handleException();
115         }
116
117         // Detect number of xps
118         struct perf_event_attr pea;
119         memset(&pea, 0, sizeof(pea));
120         pea.type = type;
121         pea.size = sizeof(pea);
122
123         mXpCount = 1;
124         while (true) {
125                 pea.config = getConfig(0, 0x08, 1, 0, 1) | mXpCount;
126                 if (!perfPoll(&pea)) {
127                         break;
128                 }
129                 mXpCount *= 2;
130         };
131         {
132                 int lower = mXpCount/2 + 1;
133                 while (lower < mXpCount) {
134                         int mid = (lower + mXpCount)/2;
135                         pea.config = getConfig(0, 0x08, 1, 0, 1) | mid;
136                         if (perfPoll(&pea)) {
137                                 lower = mid + 1;
138                         } else {
139                                 mXpCount = mid;
140                         }
141                 }
142         }
143
144         mNodeTypes = new NodeType[2*mXpCount];
145
146         // Detect node types
147         for (int i = 0; i < 2*mXpCount; ++i) {
148                 pea.config = getConfig(0, 0x04, 1, 0, 0) | i;
149                 if (perfPoll(&pea)) {
150                         mNodeTypes[i] = NT_HNF;
151                         continue;
152                 }
153
154                 pea.config = getConfig(0, 0x16, 1, 0, 0) | i;
155                 if (perfPoll(&pea)) {
156                         mNodeTypes[i] = NT_RNI;
157                         continue;
158                 }
159
160                 pea.config = getConfig(0, 0x10, 1, 0, 0) | i;
161                 if (perfPoll(&pea)) {
162                         mNodeTypes[i] = NT_SBAS;
163                         continue;
164                 }
165
166                 mNodeTypes[i] = NT_UNKNOWN;
167         }
168 }
169
170 int CCNDriver::writeCounters(mxml_node_t *const) const {
171         // Handled by PerfDriver
172         return 0;
173 }
174
175 void CCNDriver::writeEvents(mxml_node_t *const root) const {
176         mxml_node_t *const counter_set = mxmlNewElement(root, TAG_COUNTER_SET);
177         mxmlElementSetAttr(counter_set, ATTR_NAME, ARM_CCN_5XX "cnt");
178         mxmlElementSetAttr(counter_set, ATTR_COUNT, "8");
179
180         mxml_node_t *const category = mxmlNewElement(root, TAG_CATEGORY);
181         mxmlElementSetAttr(category, ATTR_NAME, CCN_5XX);
182         mxmlElementSetAttr(category, TAG_COUNTER_SET, ARM_CCN_5XX "cnt");
183
184         mxml_node_t *const clock_event = mxmlNewElement(category, TAG_EVENT);
185         mxmlElementSetAttr(clock_event, ATTR_COUNTER, ARM_CCN_5XX "ccnt");
186         mxmlElementSetAttr(clock_event, ATTR_EVENT, "0xff00");
187         mxmlElementSetAttr(clock_event, ATTR_TITLE, "CCN-5xx Clock");
188         mxmlElementSetAttr(clock_event, ATTR_NAME, "Cycles");
189         mxmlElementSetAttr(clock_event, ATTR_DISPLAY, "hertz");
190         mxmlElementSetAttr(clock_event, ATTR_UNITS, "Hz");
191         mxmlElementSetAttr(clock_event, ATTR_AVERAGE_SELECTION, "yes");
192         mxmlElementSetAttr(clock_event, ATTR_DESCRIPTION, "The number of core clock cycles");
193
194         mxml_node_t *const xp_option_set = mxmlNewElement(category, TAG_OPTION_SET);
195         mxmlElementSetAttr(xp_option_set, ATTR_NAME, XP_REGION);
196
197         for (int i = 0; i < mXpCount; ++i) {
198                 mxml_node_t *const option = mxmlNewElement(xp_option_set, TAG_OPTION);
199                 mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
200                 mxmlElementSetAttrf(option, ATTR_NAME, "XP %i", i);
201                 mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Crosspoint %i", i);
202         }
203
204         for (int vc = 0; vc < ARRAY_LENGTH(VC_TYPES); ++vc) {
205                 if (VC_TYPES[vc] == NULL) {
206                         continue;
207                 }
208                 for (int bus = 0; bus < 2; ++bus) {
209                         for (int eventId = 0; eventId < ARRAY_LENGTH(XP_EVENT_NAMES); ++eventId) {
210                                 if (XP_EVENT_NAMES[eventId] == NULL) {
211                                         continue;
212                                 }
213                                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
214                                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x08, eventId, bus, vc));
215                                 mxmlElementSetAttr(event, ATTR_OPTION_SET, XP_REGION);
216                                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
217                                 mxmlElementSetAttrf(event, ATTR_NAME, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_NAMES[eventId]);
218                                 mxmlElementSetAttrf(event, ATTR_DESCRIPTION, "Bus %i: %s: %s", bus, VC_TYPES[vc], XP_EVENT_DESCRIPTIONS[eventId]);
219                         }
220                 }
221         }
222
223         mxml_node_t *const hnf_option_set = mxmlNewElement(category, TAG_OPTION_SET);
224         mxmlElementSetAttr(hnf_option_set, ATTR_NAME, HNF_REGION);
225
226         for (int eventId = 0; eventId < ARRAY_LENGTH(HNF_EVENT_NAMES); ++eventId) {
227                 if (HNF_EVENT_NAMES[eventId] == NULL) {
228                         continue;
229                 }
230                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
231                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x04, eventId, 0, 0));
232                 mxmlElementSetAttr(event, ATTR_OPTION_SET, HNF_REGION);
233                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
234                 mxmlElementSetAttr(event, ATTR_NAME, HNF_EVENT_NAMES[eventId]);
235                 mxmlElementSetAttr(event, ATTR_DESCRIPTION, HNF_EVENT_DESCRIPTIONS[eventId]);
236         }
237
238         mxml_node_t *const rni_option_set = mxmlNewElement(category, TAG_OPTION_SET);
239         mxmlElementSetAttr(rni_option_set, ATTR_NAME, RNI_REGION);
240
241         for (int eventId = 0; eventId < ARRAY_LENGTH(RNI_EVENT_NAMES); ++eventId) {
242                 if (RNI_EVENT_NAMES[eventId] == NULL) {
243                         continue;
244                 }
245                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
246                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x16, eventId, 0, 0));
247                 mxmlElementSetAttr(event, ATTR_OPTION_SET, RNI_REGION);
248                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
249                 mxmlElementSetAttr(event, ATTR_NAME, RNI_EVENT_NAMES[eventId]);
250                 mxmlElementSetAttr(event, ATTR_DESCRIPTION, RNI_EVENT_DESCRIPTIONS[eventId]);
251         }
252
253         mxml_node_t *const sbas_option_set = mxmlNewElement(category, TAG_OPTION_SET);
254         mxmlElementSetAttr(sbas_option_set, ATTR_NAME, SBAS_REGION);
255
256         for (int eventId = 0; eventId < ARRAY_LENGTH(SBAS_EVENT_NAMES); ++eventId) {
257                 if (SBAS_EVENT_NAMES[eventId] == NULL) {
258                         continue;
259                 }
260                 mxml_node_t *const event = mxmlNewElement(category, TAG_EVENT);
261                 mxmlElementSetAttrf(event, ATTR_EVENT, "0x%x", getConfig(0, 0x10, eventId, 0, 0));
262                 mxmlElementSetAttr(event, ATTR_OPTION_SET, SBAS_REGION);
263                 mxmlElementSetAttr(event, ATTR_TITLE, CCN_5XX);
264                 mxmlElementSetAttr(event, ATTR_NAME, SBAS_EVENT_NAMES[eventId]);
265                 mxmlElementSetAttr(event, ATTR_DESCRIPTION, SBAS_EVENT_DESCRIPTIONS[eventId]);
266         }
267
268         for (int i = 0; i < 2*mXpCount; ++i) {
269                 switch (mNodeTypes[i]) {
270                 case NT_HNF: {
271                         mxml_node_t *const option = mxmlNewElement(hnf_option_set, TAG_OPTION);
272                         mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
273                         mxmlElementSetAttrf(option, ATTR_NAME, "HN-F %i", i);
274                         mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "Fully-coherent Home Node %i", i);
275                         break;
276                 }
277                 case NT_RNI: {
278                         mxml_node_t *const option = mxmlNewElement(rni_option_set, TAG_OPTION);
279                         mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
280                         mxmlElementSetAttrf(option, ATTR_NAME, "RN-I %i", i);
281                         mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "I/O-coherent Requesting Node %i", i);
282                         break;
283                 }
284                 case NT_SBAS: {
285                         mxml_node_t *const option = mxmlNewElement(sbas_option_set, TAG_OPTION);
286                         mxmlElementSetAttrf(option, ATTR_EVENT_DELTA, "0x%x", getConfig(i, 0, 0, 0, 0));
287                         mxmlElementSetAttrf(option, ATTR_NAME, "SBAS %i", i);
288                         mxmlElementSetAttrf(option, ATTR_DESCRIPTION, "ACE master to CHI protocol bridge %i", i);
289                         break;
290                 }
291                 default:
292                         continue;
293                 }
294         }
295 }