#!/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()