blob: 358bd65999762cb8d9fd4ee566526f7af921fe75 [file] [log] [blame]
Lei YUa03e55e2018-08-03 17:43:25 +08001#!/usr/bin/env python3
2
3import yaml
4import argparse
5
Lei YUd4051652018-08-06 17:02:00 +08006from typing import NamedTuple
7
8
9class RptSensor(NamedTuple):
10 name: str
11 entityId: int
12 typeId: int
13 evtType: int
14 sensorId: int
15 fru: int
16 targetPath: str
17
18
Lei YU206f7c42018-08-07 15:12:19 +080019sampleDimmTemp = {
20 'bExp': 0,
21 'entityID': 32,
22 'entityInstance': 2,
23 'interfaces': {
24 'xyz.openbmc_project.Sensor.Value': {
25 'Value': {
26 'Offsets': {
27 255: {
28 'type': 'int64_t'
29 }
30 }
31 }
32 }
33 },
34 'multiplierM': 1,
35 'mutability': 'Mutability::Write|Mutability::Read',
36 'offsetB': -127,
37 'path': '/xyz/openbmc_project/sensors/temperature/dimm0_temp',
38 'rExp': 0,
39 'readingType': 'readingData',
40 'scale': -3,
41 'sensorNamePattern': 'nameLeaf',
42 'sensorReadingType': 1,
43 'sensorType': 1,
44 'serviceInterface': 'org.freedesktop.DBus.Properties',
45 'unit': 'xyz.openbmc_project.Sensor.Value.Unit.DegreesC'
46}
47sampleCoreTemp = {
48 'bExp': 0,
49 'entityID': 208,
50 'entityInstance': 2,
51 'interfaces': {
52 'xyz.openbmc_project.Sensor.Value': {
53 'Value': {
54 'Offsets': {
55 255: {
56 'type': 'int64_t'
57 }
58 }
59 }
60 }
61 },
62 'multiplierM': 1,
63 'mutability': 'Mutability::Write|Mutability::Read',
64 'offsetB': -127,
65 'path': '/xyz/openbmc_project/sensors/temperature/p0_core0_temp',
66 'rExp': 0,
67 'readingType': 'readingData',
68 'scale': -3,
69 'sensorNamePattern': 'nameLeaf',
70 'sensorReadingType': 1,
71 'sensorType': 1,
72 'serviceInterface': 'org.freedesktop.DBus.Properties',
73 'unit': 'xyz.openbmc_project.Sensor.Value.Unit.DegreesC'
74}
Lei YU4c7f1082018-08-23 16:25:58 +080075samplePower = {
76 'bExp': 0,
77 'entityID': 10,
78 'entityInstance': 13,
79 'interfaces': {
80 'xyz.openbmc_project.Sensor.Value': {
81 'Value': {
82 'Offsets': {
83 255: {
84 'type': 'int64_t'
85 }
86 }
87 }
88 }
89 },
90 'multiplierM': 2,
91 'offsetB': 0,
92 'path': '/xyz/openbmc_project/sensors/power/p0_power',
93 'rExp': 0,
94 'readingType': 'readingData',
95 'scale': -6,
96 'sensorNamePattern': 'nameLeaf',
97 'sensorReadingType': 1,
98 'sensorType': 8,
99 'serviceInterface': 'org.freedesktop.DBus.Properties',
100 'unit': 'xyz.openbmc_project.Sensor.Value.Unit.Watts'
101}
102
Lei YUa49f04f2018-08-09 15:14:53 +0800103sampleDcmiSensor = {
104 "instance": 1,
105 "dbus": "/xyz/openbmc_project/sensors/temperature/p0_core0_temp",
106 "record_id": 91
107}
Lei YU206f7c42018-08-07 15:12:19 +0800108
109
Lei YUa03e55e2018-08-03 17:43:25 +0800110def openYaml(f):
111 return yaml.load(open(f))
112
113
Lei YUdf0c4172018-08-08 10:42:08 +0800114def saveYaml(y, f, safe=True):
115 if safe:
116 noaliasDumper = yaml.dumper.SafeDumper
117 noaliasDumper.ignore_aliases = lambda self, data: True
118 yaml.dump(y, open(f, "w"), default_flow_style=False,
119 Dumper=noaliasDumper)
120 else:
121 yaml.dump(y, open(f, "w"))
Lei YUa03e55e2018-08-03 17:43:25 +0800122
123
Lei YU9f394032018-08-08 11:25:21 +0800124def getEntityIdAndNamePattern(p, intfs, m):
125 key = (p, intfs)
126 match = m.get(key, None)
127 if match is None:
Lei YU25ecc552018-08-23 14:20:45 +0800128 # Workaround for P8's occ sensors, where the path look like
129 # /org/open_power/control/occ_3_0050
130 if '/org/open_power/control/occ' in p \
131 and 'org.open_power.OCC.Status' in intfs:
132 return (210, 'nameLeaf')
Lei YU9f394032018-08-08 11:25:21 +0800133 raise Exception('Unable to find sensor', key, 'from map')
134 return (m[key]['entityID'], m[key]['sensorNamePattern'])
Lei YUa03e55e2018-08-03 17:43:25 +0800135
136
137# Global entity instances
138entityInstances = {}
139
140
141def getEntityInstance(id):
142 instanceId = entityInstances.get(id, 0)
143 instanceId = instanceId + 1
144 entityInstances[id] = instanceId
145 print("EntityId:", id, "InstanceId:", instanceId)
146 return instanceId
147
148
Lei YUd4051652018-08-06 17:02:00 +0800149def loadRpt(rptFile):
150 sensors = []
151 with open(rptFile) as f:
152 next(f)
153 next(f)
154 for line in f:
155 fields = line.strip().split('|')
156 fields = list(map(str.strip, fields))
157 sensor = RptSensor(
158 fields[0],
159 int(fields[2], 16) if fields[2] else None,
160 int(fields[3], 16) if fields[3] else None,
161 int(fields[4], 16) if fields[4] else None,
162 int(fields[5], 16) if fields[5] else None,
163 int(fields[7], 16) if fields[7] else None,
164 fields[9])
165 # print(sensor)
166 sensors.append(sensor)
167 return sensors
168
169
Lei YU206f7c42018-08-07 15:12:19 +0800170def getDimmTempPath(p):
171 # Convert path like: /sys-0/node-0/motherboard-0/dimmconn-0/dimm-0
172 # to: /xyz/openbmc_project/sensors/temperature/dimm0_temp
173 import re
174 dimmconn = re.search(r'dimmconn-\d+', p).group()
175 dimmId = re.search(r'\d+', dimmconn).group()
176 return '/xyz/openbmc_project/sensors/temperature/dimm{}_temp'.format(dimmId)
177
178
Lei YU25ecc552018-08-23 14:20:45 +0800179def getMembufTempPath(name):
180 # Convert names like MEMBUF0_Temp or CENTAUR0_Temp
181 # to: /xyz/openbmc_project/sensors/temperature/membuf0_temp
182 # to: /xyz/openbmc_project/sensors/temperature/centaur0_temp
183 return '/xyz/openbmc_project/sensors/temperature/{}'.format(name.lower())
184
185
186def getCoreTempPath(name, p):
187 # For different rpts:
188 # Convert path like:
189 # /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/eq0/ex0/core0 (for P9)
Lei YU206f7c42018-08-07 15:12:19 +0800190 # to: /xyz/openbmc_project/sensors/temperature/p0_core0_temp
Lei YU25ecc552018-08-23 14:20:45 +0800191 # or name like: CORE0_Temp (for P8)
192 # to: /xyz/openbmc_project/sensors/temperature/core0_temp (for P8)
Lei YU206f7c42018-08-07 15:12:19 +0800193 import re
Lei YU25ecc552018-08-23 14:20:45 +0800194 if 'p9_proc' in p:
195 splitted = p.split('/')
196 socket = re.search(r'\d+', splitted[4]).group()
197 core = re.search(r'\d+', splitted[9]).group()
198 return '/xyz/openbmc_project/sensors/temperature/p{}_core{}_temp'.format(socket, core)
199 else:
200 core = re.search(r'\d+', name).group()
201 return '/xyz/openbmc_project/sensors/temperature/core{}_temp'.format(core)
Lei YU206f7c42018-08-07 15:12:19 +0800202
203
Lei YU4c7f1082018-08-23 16:25:58 +0800204def getPowerPath(name):
205 # Convert name like Proc0_Power
206 # to: /xyz/openbmc_project/sensors/power/p0_power
207 import re
208 r = re.search(r'\d+', name)
209 if r:
210 index = r.group()
211 else:
212 # Handle cases like IO_A_Power, Storage_Power_A
213 r = re.search(r'_[A|B|C|D]', name).group()[-1]
214 index = str(ord(r) - ord('A'))
215 prefix = 'p'
216 m = None
217 if 'memory_proc' in name.lower():
218 prefix = None
219 m = 'centaur'
220 elif 'pcie_proc' in name.lower():
221 m = 'pcie'
222 elif 'io' in name.lower():
223 m = 'io'
224 elif 'fan' in name.lower():
225 m = 'fan'
226 elif 'storage' in name.lower():
227 m = 'disk'
228 elif 'total' in name.lower():
229 prefix = None
230 m = 'total'
231 elif 'proc' in name.lower():
232 # Default
233 pass
234
235 ret = '/xyz/openbmc_project/sensors/power/'
236 if prefix:
237 ret = ret + prefix + index
238 if m:
239 if prefix:
240 ret = ret + '_' + m
241 else:
242 ret = ret + m
243 if prefix is None:
244 ret = ret + index
245 ret = ret + '_power'
246 return ret
247
248
Lei YU206f7c42018-08-07 15:12:19 +0800249def getDimmTempConfig(s):
250 r = sampleDimmTemp.copy()
251 r['entityInstance'] = getEntityInstance(r['entityID'])
252 r['path'] = getDimmTempPath(s.targetPath)
253 return r
254
255
Lei YU25ecc552018-08-23 14:20:45 +0800256def getMembufTempConfig(s):
257 r = sampleDimmTemp.copy()
258 r['entityID'] = 0xD1
259 r['entityInstance'] = getEntityInstance(r['entityID'])
260 r['path'] = getMembufTempPath(s.name)
261 return r
262
263
Lei YU206f7c42018-08-07 15:12:19 +0800264def getCoreTempConfig(s):
265 r = sampleCoreTemp.copy()
266 r['entityInstance'] = getEntityInstance(r['entityID'])
Lei YU25ecc552018-08-23 14:20:45 +0800267 r['path'] = getCoreTempPath(s.name, s.targetPath)
Lei YU206f7c42018-08-07 15:12:19 +0800268 return r
269
270
Lei YU4c7f1082018-08-23 16:25:58 +0800271def getPowerConfig(s):
272 r = samplePower.copy()
273 r['entityInstance'] = getEntityInstance(r['entityID'])
274 r['path'] = getPowerPath(s.name)
275 return r
276
277
Lei YUa49f04f2018-08-09 15:14:53 +0800278def isCoreTemp(p):
279 import re
280 m = re.search(r'p\d+_core\d+_temp', p)
281 return m is not None
282
283
284def getDcmiSensor(i, sensor):
285 import re
286 path = sensor['path']
287 name = path.split('/')[-1]
288 m = re.findall(r'\d+', name)
289 socket, core = int(m[0]), int(m[1])
290 instance = socket * 24 + core + 1
291 r = sampleDcmiSensor.copy()
292 r['instance'] = instance
293 r['dbus'] = path
294 r['record_id'] = i
295 return r
296
297
298def saveJson(data, f):
299 import json
300 with open(f, 'w') as outfile:
301 json.dump(data, outfile, indent=4)
302
303
Lei YUa03e55e2018-08-03 17:43:25 +0800304def main():
305 parser = argparse.ArgumentParser(
306 description='Yaml tool for updating ipmi sensor yaml config')
307 parser.add_argument('-i', '--input', required=True, dest='input',
308 help='The ipmi sensor yaml config')
309 parser.add_argument('-o', '--output', required=True, dest='output',
310 help='The output yaml file')
Lei YU9f394032018-08-08 11:25:21 +0800311 parser.add_argument('-m', '--map', dest='map', default='sensor_map.yaml',
312 help='The sample map yaml file')
Lei YUa03e55e2018-08-03 17:43:25 +0800313 parser.add_argument('-r', '--rpt', dest='rpt',
314 help='The .rpt file generated by op-build')
Lei YU9f394032018-08-08 11:25:21 +0800315 parser.add_argument('-f', '--fix', action='store_true',
316 help='Fix entities and sensorNamePattern')
Lei YUa49f04f2018-08-09 15:14:53 +0800317
318 # -g expects output as yaml for mapping of entityID/sensorNamePattern
319 # -d expects output as json config for dcmi sensors
320 # Do not mess the output by enforcing only one argument is passed
321 # TODO: -f and -r could be used together, and they are conflicted with -g or -d
322 group = parser.add_mutually_exclusive_group()
323 group.add_argument('-g', '--generate', action='store_true',
324 help='Generate maps for entityID and sensorNamePattern')
325 group.add_argument('-d', '--dcmi', action='store_true',
326 help='Generate dcmi sensors json config')
Lei YUa03e55e2018-08-03 17:43:25 +0800327
328 args = parser.parse_args()
329 args = vars(args)
330
331 if args['input'] is None or args['output'] is None:
332 parser.print_help()
333 exit(1)
334
Lei YUa03e55e2018-08-03 17:43:25 +0800335 y = openYaml(args['input'])
336
Lei YU9f394032018-08-08 11:25:21 +0800337 if args['fix']:
338 # Fix entities and sensorNamePattern
339 m = openYaml(args['map'])
340
Lei YUa03e55e2018-08-03 17:43:25 +0800341 for i in y:
342 path = y[i]['path']
Lei YU9f394032018-08-08 11:25:21 +0800343 intfs = tuple(sorted(list(y[i]['interfaces'].keys())))
344 entityId, namePattern = getEntityIdAndNamePattern(path, intfs, m)
Lei YUa03e55e2018-08-03 17:43:25 +0800345 y[i]['entityID'] = entityId
346 y[i]['entityInstance'] = getEntityInstance(entityId)
Lei YU9f394032018-08-08 11:25:21 +0800347 y[i]['sensorNamePattern'] = namePattern
Lei YUa03e55e2018-08-03 17:43:25 +0800348 print(y[i]['path'], "id:", entityId,
349 "instance:", y[i]['entityInstance'])
350
Lei YU206f7c42018-08-07 15:12:19 +0800351 sensorIds = list(y.keys())
352 if args['rpt']:
Lei YU25ecc552018-08-23 14:20:45 +0800353 unhandledSensors = []
Lei YU206f7c42018-08-07 15:12:19 +0800354 rptSensors = loadRpt(args['rpt'])
355 for s in rptSensors:
356 if s.sensorId is not None and s.sensorId not in sensorIds:
357 print("Sensor ID", s.sensorId, "not in yaml:",
358 s.name, ", path:", s.targetPath)
Lei YU4c7f1082018-08-23 16:25:58 +0800359 isAdded = False
Lei YU206f7c42018-08-07 15:12:19 +0800360 if 'temp' in s.name.lower():
361 if 'dimm' in s.targetPath.lower():
362 y[s.sensorId] = getDimmTempConfig(s)
Lei YU4c7f1082018-08-23 16:25:58 +0800363 isAdded = True
Lei YU25ecc552018-08-23 14:20:45 +0800364 elif 'core' in s.targetPath.lower():
Lei YU206f7c42018-08-07 15:12:19 +0800365 y[s.sensorId] = getCoreTempConfig(s)
Lei YU4c7f1082018-08-23 16:25:58 +0800366 isAdded = True
Lei YU25ecc552018-08-23 14:20:45 +0800367 elif 'centaur' in s.name.lower() or 'membuf' in s.name.lower():
368 y[s.sensorId] = getMembufTempConfig(s)
Lei YU4c7f1082018-08-23 16:25:58 +0800369 isAdded = True
370 elif s.name.lower().endswith('_power'):
371 y[s.sensorId] = getPowerConfig(s)
372 isAdded = True
373
374 if isAdded:
375 print('Added sensor id:', s.sensorId,
376 ', path:', y[s.sensorId]['path'])
Lei YU25ecc552018-08-23 14:20:45 +0800377 else:
378 unhandledSensors.append(s)
379
380 print('Unhandled sensors:')
381 for s in unhandledSensors:
382 print(s)
Lei YU206f7c42018-08-07 15:12:19 +0800383
Lei YUdf0c4172018-08-08 10:42:08 +0800384 if args['generate']:
385 m = {}
386 for i in y:
387 path = y[i]['path']
388 intfs = tuple(sorted(list(y[i]['interfaces'].keys())))
389 entityId = y[i]['entityID']
390 sensorNamePattern = y[i]['sensorNamePattern']
391 m[(path, intfs)] = {'entityID': entityId,
392 'sensorNamePattern': sensorNamePattern}
393 y = m
394
Lei YUa49f04f2018-08-09 15:14:53 +0800395 if args['dcmi']:
396 d = []
397 for i in y:
398 if isCoreTemp(y[i]['path']):
399 s = getDcmiSensor(i, y[i])
400 d.append(s)
401 print(s)
402 saveJson(d, args['output'])
403 return
Lei YUdf0c4172018-08-08 10:42:08 +0800404
Lei YUa49f04f2018-08-09 15:14:53 +0800405 safe = False if args['generate'] else True
Lei YUdf0c4172018-08-08 10:42:08 +0800406 saveYaml(y, args['output'], safe)
Lei YUa03e55e2018-08-03 17:43:25 +0800407
408
409if __name__ == "__main__":
410 main()