#!/usr/bin/env python # # Copyright (C) 2018 Inventec, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import os import time import syslog import re from sonic_sfp.bcmshell import bcmshell # ===================================================================== # global variable init # ===================================================================== # port object PORT_LIST = [] # object is to execute bcm shell command BCM_SHELL = None SHELL_READY = False # port status that is auto update by chip in data ram STATUS_RX = 1<<0 STATUS_TX = 1<<1 # define data ram address PORT_DATA_OFFSET_ADDR = 0xA0 # define board type INV_MAGNOLIA = "SONiC-Inventec-d6254qs" INV_REDWOOD = "SONiC-Inventec-d7032-100" INV_CYPRESS = "SONiC-Inventec-d7054" INV_MAPLE = "SONiC-Inventec-d6556" INV_SEQUOIA = "" BOARD_TPYE = "" EAGLE_CORE = [] # 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 # ===================================================================== # class object # ===================================================================== class Port(): port_num = None name = None bcm_id = None led_up = None s_addr = None write2_up = None led_index = None link_status = None speed = None def write_data_ram(self, data): BCM_SHELL.cmd("setreg CMIC_LEDUP{0}_DATA_RAM({1}) {2}".format(self.write2_up, self.led_index, data)) def read_data_ram(self): r_string = BCM_SHELL.run("getreg CMIC_LEDUP{0}_DATA_RAM({1})".format(self.led_up, self.s_addr)) for line in r_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, addr, re_obj.group("data"))) return int(re_obj.group("data"), 16) # ===================================================================== # Function # ===================================================================== def _remap_registers(fp): 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: syslog.syslog(syslog.LOG_INFO, "remap Led registers successfully") def _board_init(): global BOARD_TPYE 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_MAGNOLIA: BOARD_TPYE = "inventec_d6254qs" BIT_RX = 1<<0 #0x01 BIT_TX = 1<<1 #0x02 BIT_SPEED1 = 1<<4 #0x10 BIT_LINK = 1<<7 #0x80 fp = open('/usr/share/sonic/device/x86_64-inventec_d6254qs-r0/led_proc_init.soc', "r") _remap_registers(fp) elif platform.rstrip() == INV_REDWOOD: BOARD_TPYE = "inventec_d7032q28b" 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 EAGLE_CORE = [66, 100] fp = open('/usr/share/sonic/device/x86_64-inventec_d7032q28b-r0/led_proc_init.soc', "r") _remap_registers(fp) elif platform.rstrip() == INV_CYPRESS: BOARD_TPYE = "inventec_d7054q28b" 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" elif platform.rstrip() == INV_MAPLE: BOARD_TPYE = "inventec_d6556" fp = open('/usr/share/sonic/device/x86_64-inventec_d6556-r0/led_proc_init.soc', "r") _remap_registers(fp) #led process: m0 led process that is controlled by linkscan_led_fw.bin and custom_led.bin syslog.syslog(syslog.LOG_INFO, "Found device: {0}".format(BOARD_TPYE)) exit(0) else: BOARD_TPYE = "not found" syslog.syslog(syslog.LOG_ERR, "Found device: {0}".format(BOARD_TPYE)) exit(0) syslog.syslog(syslog.LOG_INFO, "Found device: {0}".format(BOARD_TPYE)) def _lookup_led_index(p): index = 0 if BOARD_TPYE == "inventec_d6254qs": if 0 <= p.port_num <= 47: index = p.port_num + (p.port_num / 4) p.write2_up = 0 elif 48 <= p.port_num <= 71: index = p.port_num - 48 p.write2_up = 1 if p.led_up == 0: p.s_addr = p.port_num * 2 elif p.led_up == 1: p.s_addr = (p.port_num - 36) * 2 elif BOARD_TPYE == "inventec_d7032q28b": p.write2_up = 0 index = p.port_num if 0 <= p.port_num <= 7: p.s_addr = p.port_num * 8 elif 8 <= p.port_num <= 23: p.s_addr = (p.port_num - 8) * 8 elif 24 <= p.port_num <= 31: p.s_addr = (p.port_num - 16) * 8 else: p.write2_up = p.led_up for port in PORT_LIST: if p.bcm_id == port.bcm_id: break if p.led_up == port.led_up: index += 1 return PORT_DATA_OFFSET_ADDR + index def _update_port_list(only_update): global 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: if only_update: PORT_LIST[number].link_status = re_obj.group("link") else: # create port object while first time port_obj = Port() port_obj.port_num = number port_obj.name = re_obj.group("port_name") port_obj.bcm_id = int(re_obj.group("bcm_id")) port_obj.link_status = re_obj.group("link") port_obj.speed = int(re_obj.group("speed")) PORT_LIST.append(port_obj) number += 1 if not only_update: content = BCM_SHELL.run("led status") for line in content.split("\n"): re_obj = re.search(r"(?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].led_index = _lookup_led_index(PORT_LIST[count]) count += 1 if number is not count: PORT_LIST = [] syslog.syslog(syslog.LOG_ERR, "The amount of port is not match") def sync_bcmsh_socket(): global BCM_SHELL global SHELL_READY waitSyncd = True retryCount = 0 while waitSyncd: time.sleep(10) try: BCM_SHELL = bcmshell() BCM_SHELL.run("Echo") waitSyncd = False except Exception, e: print "{0}, Retry times({1})".format(str(e),retryCount) #syslog.syslog(syslog.LOG_DEBUG, "{0}, Retry times({1})".format(str(e),retryCount)) retryCount += 1 syslog.syslog(syslog.LOG_INFO, "bcmshell socket create successfully") if SHELL_READY is False: SHELL_READY = True return elif SHELL_READY is True: update_led_status() def update_led_status(): led_thread = True # True/False (gate to turn on/off) reset_sec = 2 count_down = 0 queue_active = [] port_data = None s_byte = None # thread for keeping update port status in data ram while led_thread: try: if count_down == 0: queue_active = [] _update_port_list(1) for port in PORT_LIST: if port.link_status == "up": queue_active.append(port) else: port_data = 0 port.write_data_ram(port_data) count_down = reset_sec else: for port in queue_active: port_data = 0 if BOARD_TPYE == "inventec_d6254qs": s_byte = port.read_data_ram() if s_byte&STATUS_RX: port_data |= BIT_RX if s_byte&STATUS_TX: port_data |= BIT_TX port_data |= BIT_LINK elif BOARD_TPYE == "inventec_d7032q28b": s_byte = port.read_data_ram() if s_byte&STATUS_RX: port_data |= BIT_RX if s_byte&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 port_data |= BIT_LINK elif BOARD_TPYE == "inventec_d7054q28b": if port.speed != SPEED_100G and port.speed != SPEED_25G: port_data |= BIT_SPEED0 # write data to update data ram for specific port port.write_data_ram(port_data) time.sleep(0.5) count_down -= 1 except Exception, e: syslog.syslog(syslog.LOG_WARNING, "{0}".format(str(e))) sync_bcmsh_socket() def debug_print(): for port in PORT_LIST: output = "" output += "name:{0} | ".format(port.name) output += "port_num:{0} | ".format(port.port_num) output += "bcm_id:{0} | ".format(port.bcm_id) output += "link_status:{0} | ".format(port.link_status) output += "speed:{0} | ".format(port.speed) output += "led_up:{0} | ".format(port.led_up) output += "s_addr:{0} | ".format(port.s_addr) output += "write2_up:{0} | ".format(port.write2_up) output += "led_index:{0} | ".format(port.led_index) print output if __name__ == "__main__": syslog.openlog("led_proc", syslog.LOG_PID, facility=syslog.LOG_DAEMON) sync_bcmsh_socket() _board_init() _update_port_list(0) #debug_print() update_led_status() syslog.closelog()