| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
|  | 2 |  | 
|  | 3 | import yaml | 
|  | 4 | import argparse | 
|  | 5 |  | 
| Lei YU | d405165 | 2018-08-06 17:02:00 +0800 | [diff] [blame] | 6 | from typing import NamedTuple | 
|  | 7 |  | 
|  | 8 |  | 
|  | 9 | class 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 YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 19 | sampleDimmTemp = { | 
|  | 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 | } | 
|  | 47 | sampleCoreTemp = { | 
|  | 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 YU | a49f04f | 2018-08-09 15:14:53 +0800 | [diff] [blame] | 75 | sampleDcmiSensor = { | 
|  | 76 | "instance": 1, | 
|  | 77 | "dbus": "/xyz/openbmc_project/sensors/temperature/p0_core0_temp", | 
|  | 78 | "record_id": 91 | 
|  | 79 | } | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 80 |  | 
|  | 81 |  | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 82 | def openYaml(f): | 
|  | 83 | return yaml.load(open(f)) | 
|  | 84 |  | 
|  | 85 |  | 
| Lei YU | df0c417 | 2018-08-08 10:42:08 +0800 | [diff] [blame] | 86 | def saveYaml(y, f, safe=True): | 
|  | 87 | if safe: | 
|  | 88 | noaliasDumper = yaml.dumper.SafeDumper | 
|  | 89 | noaliasDumper.ignore_aliases = lambda self, data: True | 
|  | 90 | yaml.dump(y, open(f, "w"), default_flow_style=False, | 
|  | 91 | Dumper=noaliasDumper) | 
|  | 92 | else: | 
|  | 93 | yaml.dump(y, open(f, "w")) | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 94 |  | 
|  | 95 |  | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 96 | def getEntityIdAndNamePattern(p, intfs, m): | 
|  | 97 | key = (p, intfs) | 
|  | 98 | match = m.get(key, None) | 
|  | 99 | if match is None: | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 100 | # Workaround for P8's occ sensors, where the path look like | 
|  | 101 | # /org/open_power/control/occ_3_0050 | 
|  | 102 | if '/org/open_power/control/occ' in p \ | 
|  | 103 | and 'org.open_power.OCC.Status' in intfs: | 
|  | 104 | return (210, 'nameLeaf') | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 105 | raise Exception('Unable to find sensor', key, 'from map') | 
|  | 106 | return (m[key]['entityID'], m[key]['sensorNamePattern']) | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 107 |  | 
|  | 108 |  | 
|  | 109 | # Global entity instances | 
|  | 110 | entityInstances = {} | 
|  | 111 |  | 
|  | 112 |  | 
|  | 113 | def getEntityInstance(id): | 
|  | 114 | instanceId = entityInstances.get(id, 0) | 
|  | 115 | instanceId = instanceId + 1 | 
|  | 116 | entityInstances[id] = instanceId | 
|  | 117 | print("EntityId:", id, "InstanceId:", instanceId) | 
|  | 118 | return instanceId | 
|  | 119 |  | 
|  | 120 |  | 
| Lei YU | d405165 | 2018-08-06 17:02:00 +0800 | [diff] [blame] | 121 | def loadRpt(rptFile): | 
|  | 122 | sensors = [] | 
|  | 123 | with open(rptFile) as f: | 
|  | 124 | next(f) | 
|  | 125 | next(f) | 
|  | 126 | for line in f: | 
|  | 127 | fields = line.strip().split('|') | 
|  | 128 | fields = list(map(str.strip, fields)) | 
|  | 129 | sensor = RptSensor( | 
|  | 130 | fields[0], | 
|  | 131 | int(fields[2], 16) if fields[2] else None, | 
|  | 132 | int(fields[3], 16) if fields[3] else None, | 
|  | 133 | int(fields[4], 16) if fields[4] else None, | 
|  | 134 | int(fields[5], 16) if fields[5] else None, | 
|  | 135 | int(fields[7], 16) if fields[7] else None, | 
|  | 136 | fields[9]) | 
|  | 137 | # print(sensor) | 
|  | 138 | sensors.append(sensor) | 
|  | 139 | return sensors | 
|  | 140 |  | 
|  | 141 |  | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 142 | def getDimmTempPath(p): | 
|  | 143 | # Convert path like: /sys-0/node-0/motherboard-0/dimmconn-0/dimm-0 | 
|  | 144 | # to: /xyz/openbmc_project/sensors/temperature/dimm0_temp | 
|  | 145 | import re | 
|  | 146 | dimmconn = re.search(r'dimmconn-\d+', p).group() | 
|  | 147 | dimmId = re.search(r'\d+', dimmconn).group() | 
|  | 148 | return '/xyz/openbmc_project/sensors/temperature/dimm{}_temp'.format(dimmId) | 
|  | 149 |  | 
|  | 150 |  | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 151 | def getMembufTempPath(name): | 
|  | 152 | # Convert names like MEMBUF0_Temp or CENTAUR0_Temp | 
|  | 153 | # to: /xyz/openbmc_project/sensors/temperature/membuf0_temp | 
|  | 154 | # to: /xyz/openbmc_project/sensors/temperature/centaur0_temp | 
|  | 155 | return '/xyz/openbmc_project/sensors/temperature/{}'.format(name.lower()) | 
|  | 156 |  | 
|  | 157 |  | 
|  | 158 | def getCoreTempPath(name, p): | 
|  | 159 | # For different rpts: | 
|  | 160 | # Convert path like: | 
|  | 161 | #   /sys-0/node-0/motherboard-0/proc_socket-0/module-0/p9_proc_s/eq0/ex0/core0 (for P9) | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 162 | # to: /xyz/openbmc_project/sensors/temperature/p0_core0_temp | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 163 | # or name like: CORE0_Temp (for P8) | 
|  | 164 | # to: /xyz/openbmc_project/sensors/temperature/core0_temp (for P8) | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 165 | import re | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 166 | if 'p9_proc' in p: | 
|  | 167 | splitted = p.split('/') | 
|  | 168 | socket = re.search(r'\d+', splitted[4]).group() | 
|  | 169 | core = re.search(r'\d+', splitted[9]).group() | 
|  | 170 | return '/xyz/openbmc_project/sensors/temperature/p{}_core{}_temp'.format(socket, core) | 
|  | 171 | else: | 
|  | 172 | core = re.search(r'\d+', name).group() | 
|  | 173 | return '/xyz/openbmc_project/sensors/temperature/core{}_temp'.format(core) | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 174 |  | 
|  | 175 |  | 
|  | 176 | def getDimmTempConfig(s): | 
|  | 177 | r = sampleDimmTemp.copy() | 
|  | 178 | r['entityInstance'] = getEntityInstance(r['entityID']) | 
|  | 179 | r['path'] = getDimmTempPath(s.targetPath) | 
|  | 180 | return r | 
|  | 181 |  | 
|  | 182 |  | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 183 | def getMembufTempConfig(s): | 
|  | 184 | r = sampleDimmTemp.copy() | 
|  | 185 | r['entityID'] = 0xD1 | 
|  | 186 | r['entityInstance'] = getEntityInstance(r['entityID']) | 
|  | 187 | r['path'] = getMembufTempPath(s.name) | 
|  | 188 | return r | 
|  | 189 |  | 
|  | 190 |  | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 191 | def getCoreTempConfig(s): | 
|  | 192 | r = sampleCoreTemp.copy() | 
|  | 193 | r['entityInstance'] = getEntityInstance(r['entityID']) | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 194 | r['path'] = getCoreTempPath(s.name, s.targetPath) | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 195 | return r | 
|  | 196 |  | 
|  | 197 |  | 
| Lei YU | a49f04f | 2018-08-09 15:14:53 +0800 | [diff] [blame] | 198 | def isCoreTemp(p): | 
|  | 199 | import re | 
|  | 200 | m = re.search(r'p\d+_core\d+_temp', p) | 
|  | 201 | return m is not None | 
|  | 202 |  | 
|  | 203 |  | 
|  | 204 | def getDcmiSensor(i, sensor): | 
|  | 205 | import re | 
|  | 206 | path = sensor['path'] | 
|  | 207 | name = path.split('/')[-1] | 
|  | 208 | m = re.findall(r'\d+', name) | 
|  | 209 | socket, core = int(m[0]), int(m[1]) | 
|  | 210 | instance = socket * 24 + core + 1 | 
|  | 211 | r = sampleDcmiSensor.copy() | 
|  | 212 | r['instance'] = instance | 
|  | 213 | r['dbus'] = path | 
|  | 214 | r['record_id'] = i | 
|  | 215 | return r | 
|  | 216 |  | 
|  | 217 |  | 
|  | 218 | def saveJson(data, f): | 
|  | 219 | import json | 
|  | 220 | with open(f, 'w') as outfile: | 
|  | 221 | json.dump(data, outfile, indent=4) | 
|  | 222 |  | 
|  | 223 |  | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 224 | def main(): | 
|  | 225 | parser = argparse.ArgumentParser( | 
|  | 226 | description='Yaml tool for updating ipmi sensor yaml config') | 
|  | 227 | parser.add_argument('-i', '--input', required=True, dest='input', | 
|  | 228 | help='The ipmi sensor yaml config') | 
|  | 229 | parser.add_argument('-o', '--output', required=True, dest='output', | 
|  | 230 | help='The output yaml file') | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 231 | parser.add_argument('-m', '--map', dest='map', default='sensor_map.yaml', | 
|  | 232 | help='The sample map yaml file') | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 233 | parser.add_argument('-r', '--rpt', dest='rpt', | 
|  | 234 | help='The .rpt file generated by op-build') | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 235 | parser.add_argument('-f', '--fix', action='store_true', | 
|  | 236 | help='Fix entities and sensorNamePattern') | 
| Lei YU | a49f04f | 2018-08-09 15:14:53 +0800 | [diff] [blame] | 237 |  | 
|  | 238 | # -g expects output as yaml for mapping of entityID/sensorNamePattern | 
|  | 239 | # -d expects output as json config for dcmi sensors | 
|  | 240 | # Do not mess the output by enforcing only one argument is passed | 
|  | 241 | # TODO: -f and -r could be used together, and they are conflicted with -g or -d | 
|  | 242 | group = parser.add_mutually_exclusive_group() | 
|  | 243 | group.add_argument('-g', '--generate', action='store_true', | 
|  | 244 | help='Generate maps for entityID and sensorNamePattern') | 
|  | 245 | group.add_argument('-d', '--dcmi', action='store_true', | 
|  | 246 | help='Generate dcmi sensors json config') | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 247 |  | 
|  | 248 | args = parser.parse_args() | 
|  | 249 | args = vars(args) | 
|  | 250 |  | 
|  | 251 | if args['input'] is None or args['output'] is None: | 
|  | 252 | parser.print_help() | 
|  | 253 | exit(1) | 
|  | 254 |  | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 255 | y = openYaml(args['input']) | 
|  | 256 |  | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 257 | if args['fix']: | 
|  | 258 | # Fix entities and sensorNamePattern | 
|  | 259 | m = openYaml(args['map']) | 
|  | 260 |  | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 261 | for i in y: | 
|  | 262 | path = y[i]['path'] | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 263 | intfs = tuple(sorted(list(y[i]['interfaces'].keys()))) | 
|  | 264 | entityId, namePattern = getEntityIdAndNamePattern(path, intfs, m) | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 265 | y[i]['entityID'] = entityId | 
|  | 266 | y[i]['entityInstance'] = getEntityInstance(entityId) | 
| Lei YU | 9f39403 | 2018-08-08 11:25:21 +0800 | [diff] [blame] | 267 | y[i]['sensorNamePattern'] = namePattern | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 268 | print(y[i]['path'], "id:", entityId, | 
|  | 269 | "instance:", y[i]['entityInstance']) | 
|  | 270 |  | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 271 | sensorIds = list(y.keys()) | 
|  | 272 | if args['rpt']: | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 273 | unhandledSensors = [] | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 274 | rptSensors = loadRpt(args['rpt']) | 
|  | 275 | for s in rptSensors: | 
|  | 276 | if s.sensorId is not None and s.sensorId not in sensorIds: | 
|  | 277 | print("Sensor ID", s.sensorId, "not in yaml:", | 
|  | 278 | s.name, ", path:", s.targetPath) | 
|  | 279 | if 'temp' in s.name.lower(): | 
|  | 280 | if 'dimm' in s.targetPath.lower(): | 
|  | 281 | y[s.sensorId] = getDimmTempConfig(s) | 
|  | 282 | print('Added sensor id:', s.sensorId, | 
|  | 283 | ', path:', y[s.sensorId]['path']) | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 284 | elif 'core' in s.targetPath.lower(): | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 285 | y[s.sensorId] = getCoreTempConfig(s) | 
|  | 286 | print('Added sensor id:', s.sensorId, | 
|  | 287 | ', path:', y[s.sensorId]['path']) | 
| Lei YU | 25ecc55 | 2018-08-23 14:20:45 +0800 | [diff] [blame^] | 288 | elif 'centaur' in s.name.lower() or 'membuf' in s.name.lower(): | 
|  | 289 | y[s.sensorId] = getMembufTempConfig(s) | 
|  | 290 | print('Added sensor id:', s.sensorId, | 
|  | 291 | ', path:', y[s.sensorId]['path']) | 
|  | 292 | else: | 
|  | 293 | unhandledSensors.append(s) | 
|  | 294 | else: | 
|  | 295 | unhandledSensors.append(s) | 
|  | 296 |  | 
|  | 297 | print('Unhandled sensors:') | 
|  | 298 | for s in unhandledSensors: | 
|  | 299 | print(s) | 
| Lei YU | 206f7c4 | 2018-08-07 15:12:19 +0800 | [diff] [blame] | 300 |  | 
| Lei YU | df0c417 | 2018-08-08 10:42:08 +0800 | [diff] [blame] | 301 | if args['generate']: | 
|  | 302 | m = {} | 
|  | 303 | for i in y: | 
|  | 304 | path = y[i]['path'] | 
|  | 305 | intfs = tuple(sorted(list(y[i]['interfaces'].keys()))) | 
|  | 306 | entityId = y[i]['entityID'] | 
|  | 307 | sensorNamePattern = y[i]['sensorNamePattern'] | 
|  | 308 | m[(path, intfs)] = {'entityID': entityId, | 
|  | 309 | 'sensorNamePattern': sensorNamePattern} | 
|  | 310 | y = m | 
|  | 311 |  | 
| Lei YU | a49f04f | 2018-08-09 15:14:53 +0800 | [diff] [blame] | 312 | if args['dcmi']: | 
|  | 313 | d = [] | 
|  | 314 | for i in y: | 
|  | 315 | if isCoreTemp(y[i]['path']): | 
|  | 316 | s = getDcmiSensor(i, y[i]) | 
|  | 317 | d.append(s) | 
|  | 318 | print(s) | 
|  | 319 | saveJson(d, args['output']) | 
|  | 320 | return | 
| Lei YU | df0c417 | 2018-08-08 10:42:08 +0800 | [diff] [blame] | 321 |  | 
| Lei YU | a49f04f | 2018-08-09 15:14:53 +0800 | [diff] [blame] | 322 | safe = False if args['generate'] else True | 
| Lei YU | df0c417 | 2018-08-08 10:42:08 +0800 | [diff] [blame] | 323 | saveYaml(y, args['output'], safe) | 
| Lei YU | a03e55e | 2018-08-03 17:43:25 +0800 | [diff] [blame] | 324 |  | 
|  | 325 |  | 
|  | 326 | if __name__ == "__main__": | 
|  | 327 | main() |