#!/usr/bin/env python # import os import time import syslog import re from sonic_sfp.bcmshell import bcmshell # ===================================================================== # global variable init # ===================================================================== # define data ram address PORT_DATA_OFFSET_ADDR = 0xA0 PORT_DATA_START_ADDR = 0xF2 TOTAL_SCAN_BITS_ADDR = 0xF4 SYNC_START_LEN_ADDR = 0xF6 SYNC_STOP_LEN_ADDR = 0xF8 # bit streaming rule for CPLD decode TOTAL_SCAN_BITS = None SYNC_S = None SYNC_P = None # define port data for bit streaming BIT_LINK = None BIT_FAULT = None BIT_TX = None BIT_RX = None BIT_SPEED0 = None BIT_SPEED1 = None # define port speed SPEED_100G = 100 SPEED_40G = 40 SPEED_25G = 25 SPEED_10G = 10 # the amount of LED processor AMOUNT_LED_UP = None # define board type INV_REDWOOD = "SONiC-Inventec-d7032-100" INV_CYPRESS = "SONiC-Inventec-d7054" INV_SEQUOIA = "" BOARD_TPYE = "" EAGLE_CORE = [] PORT_LIST = [] # port status that is auto update by chip in data ram # there are two byte to indicate each port status ''' RX equ 0x0 ; received packet TX equ 0x1 ; transmitted packet COLL equ 0x2 ; collision indicator SPEED_C equ 0x3 ; 100 Mbps SPEED_M equ 0x4 ; 1000 Mbps DUPLEX equ 0x5 ; half/full duplex FLOW equ 0x6 ; flow control capable LINKUP equ 0x7 ; link down/up status LINKEN equ 0x8 ; link disabled/enabled status ZERO equ 0xE ; always 0 ONE equ 0xF ; always 1 ''' STATUS_ENABLE = 1<<0 STATUS_RX = 1<<0 STATUS_TX = 1<<1 # object is to execute bcm shell command BCM_SHELL = None # ===================================================================== # class object # ===================================================================== class Led(): up = None pfw = None def __init__(self, led_number, program_fw): self.up = led_number self.pfw = program_fw def led_start(self): BCM_SHELL.cmd("led {0} start".format(self.up)) syslog.syslog(syslog.LOG_INFO, "Start Led({0})".format(self.up)) def led_stop(self): BCM_SHELL.cmd("led {0} stop".format(self.up)) syslog.syslog(syslog.LOG_INFO, "Stop Led({0})".format(self.up)) def load_prog(self): BCM_SHELL.cmd("led {0} prog {1}".format(self.up, self.pfw)) syslog.syslog(syslog.LOG_INFO, "Load Led({0}) program firmware".format(self.up)) def write_port_data(self, addr, data): BCM_SHELL.cmd("setreg CMIC_LEDUP{0}_DATA_RAM({1}) {2}".format(self.up, addr, data)) #syslog.syslog(syslog.LOG_DEBUG, "Write Led({0}) data_ram({1}): {2}".format(self.up, addr, data)) def read_data_ram(self, offset): return_string = BCM_SHELL.run("getreg CMIC_LEDUP{0}_DATA_RAM({1})".format(self.up, offset)) for line in return_string.split("\n"): re_obj = re.search(r"\.+)\>",line) if re_obj is not None: #syslog.syslog(syslog.LOG_DEBUG, "Read Led({0}) data_ram({1}): {2}".format(self.up, offset, re_obj.group("data"))) return int(re_obj.group("data"), 16) return None # ===================================================================== # Function # ===================================================================== def _remap_registers(): fp = open('/usr/share/sonic/device/x86_64-inventec_d7032q28b-r0/led_proc_init.soc', "r") content = fp.readlines() fp.close() err = False for line in content: try: BCM_SHELL.cmd(line.rstrip()) except Exception, e: err = True syslog.syslog(syslog.LOG_ERR, "remap register abnormal: {0}".format(str(e))) if not err: pass #syslog.syslog(syslog.LOG_DEBUG, "remap Led registers successfully") def _update_port_list(): global PORT_LIST PORT_LIST = [] number = 0 count = 0 content = BCM_SHELL.run("ps") for line in content.split("\n"): re_obj = re.search(r"(?P(xe|ce)\d+)\(\s*(?P\d+)\)\s+(?P(up|down|!ena)).+\s+(?P\d+)G",line) if re_obj is not None: if int(re_obj.group("bcm_id")) not in EAGLE_CORE: PORT_LIST.append({"port_id":number, "name":re_obj.group("port_name"), "bcm_id":int(re_obj.group("bcm_id")), "link":re_obj.group("link"), "speed":int(re_obj.group("speed"))}) number += 1 content = BCM_SHELL.run("led status") for line in content.split("\n"): re_obj = re.search(r"(?P\d+).+(?P\d)\:(?P\d+)",line) if re_obj is not None: if int(re_obj.group("bcm_id")) not in EAGLE_CORE: PORT_LIST[count]["led_up"] = int(re_obj.group("led_up")) PORT_LIST[count]["offset"] = int(re_obj.group("offset")) count += 1 if number is not count: PORT_LIST = [] syslog.syslog(syslog.LOG_ERR, "The amount of port is not match") else: pass #syslog.syslog(syslog.LOG_DEBUG, "update port list successfully") def _lookup_led_index(p): index = 0 for port in PORT_LIST: if p["bcm_id"] == port["bcm_id"]: break if p["led_up"] == port["led_up"]: index += 1 return index + PORT_DATA_OFFSET_ADDR def _led_init(): global BOARD_TPYE global AMOUNT_LED_UP global BIT_LINK global BIT_FAULT global BIT_TX global BIT_RX global BIT_SPEED0 global BIT_SPEED1 global EAGLE_CORE global TOTAL_SCAN_BITS global SYNC_S global SYNC_P cmd = "uname -n" platform = os.popen(cmd).read() if platform.rstrip() == INV_REDWOOD: BOARD_TPYE = "inventec_d7032q28b" AMOUNT_LED_UP = 2 BIT_RX = 1<<0 #0x01 BIT_TX = 1<<1 #0x02 BIT_SPEED0 = 1<<3 #0x08 BIT_SPEED1 = 1<<4 #0x10 BIT_FAULT = 1<<6 #0x40 BIT_LINK = 1<<7 #0x80 TOTAL_SCAN_BITS = 32*1*4 SYNC_S = 15 SYNC_P = 3 EAGLE_CORE = [66, 100] _remap_registers() elif platform.rstrip() == INV_CYPRESS: BOARD_TPYE = "inventec_d7054q28b" AMOUNT_LED_UP = 2 BIT_LINK = 1<<0 #0x01 BIT_FAULT = 1<<1 #0x02 BIT_SPEED0 = 1<<2 #0x04 EAGLE_CORE = [66, 100] elif platform.rstrip() == INV_SEQUOIA: BOARD_TPYE = "inventec_d7264q28b" AMOUNT_LED_UP = 4 else: BOARD_TPYE = "not found" syslog.syslog(syslog.LOG_INFO, "Device: {0}".format(BOARD_TPYE)) #syslog.syslog(syslog.LOG_DEBUG, "led_amount: {0}".format(AMOUNT_LED_UP)) if __name__ == "__main__": waitSyncd = True retryCount = 0 syslog.openlog("led_proc", syslog.LOG_PID, facility=syslog.LOG_DAEMON) while waitSyncd: try: BCM_SHELL = bcmshell() waitSyncd = False except Exception, e: syslog.syslog(syslog.LOG_WARNING, "{0}, Retry times({1})".format(str(e),retryCount)) retryCount += 1 time.sleep(5) _led_init() led_obj = [] for idx in range(AMOUNT_LED_UP): led_obj.append(Led(idx, "")) #syslog.syslog(syslog.LOG_DEBUG, "create object led({0}) successfully".format(idx)) if BOARD_TPYE == "inventec_d7032q28b": led_obj[idx].write_port_data(PORT_DATA_START_ADDR, PORT_DATA_OFFSET_ADDR) led_obj[idx].write_port_data(TOTAL_SCAN_BITS_ADDR, TOTAL_SCAN_BITS) led_obj[idx].write_port_data(SYNC_START_LEN_ADDR, SYNC_S) led_obj[idx].write_port_data(SYNC_STOP_LEN_ADDR, SYNC_P) reset_sec = 2 count_down = 0 queue_active = [] port_data = None while True: if count_down == 0: queue_active = [] _update_port_list() for port in PORT_LIST: if port["link"] == "up": queue_active.append(port) else: port_data = 0 # redwood bit streaming for CPLD decode is only use led up0 led_obj[0].write_port_data(PORT_DATA_OFFSET_ADDR + port["port_id"], port_data) count_down = reset_sec else: for port in queue_active: port_data = 0 if BOARD_TPYE == "inventec_d7032q28b": port_data |= BIT_LINK addr = 2*(port["offset"]-1) byte1 = led_obj[port["led_up"]].read_data_ram(addr) byte2 = led_obj[port["led_up"]].read_data_ram(addr+1) if byte1&STATUS_RX: port_data |= BIT_RX if byte1&STATUS_TX: port_data |= BIT_TX if port["speed"] == SPEED_100G: port_data |= BIT_SPEED0 port_data |= BIT_SPEED1 elif port["speed"] == SPEED_40G: port_data |= BIT_SPEED1 elif port["speed"] == SPEED_25G: port_data |= BIT_SPEED0 else: pass # redwood bit streaming for CPLD decode is only use led up0 led_obj[0].write_port_data(PORT_DATA_OFFSET_ADDR + port["port_id"], port_data) continue elif BOARD_TPYE == "inventec_d7054q28b": if port["speed"] != SPEED_100G and port["speed"] != SPEED_25G: port_data |= BIT_SPEED0 led_index = _lookup_led_index(port) led_obj[port["led_up"]].write_port_data(led_index, port_data) time.sleep(0.5) count_down -= 1 syslog.closelog()