[devices]: Add support for the Nokia-7215 platform (#5827)

Platform: armhf-nokia_ixs7215_52x-r0
HwSKU: Nokia-7215
ASIC: marvell
Port Config: 48x1G + 4x10G

Co-authored-by: dflynn <dennis.flynn@nokia.com>
Co-authored-by: Carl Keene <keene@nokia.com>
This commit is contained in:
carl-nokia 2020-11-18 20:00:40 -05:00 committed by GitHub
parent 3be3f4d104
commit 0a9d7a2145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 4316 additions and 2 deletions

View File

@ -0,0 +1,45 @@
{%- set default_cable = '300m' %}
{%- macro generate_port_lists(PORT_ALL) %}
{# Generate list of ports #}
{% for port_idx in range(0,32) %}
{% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %}
{% endfor %}
{%- endmacro %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "12766208",
"type": "ingress",
"mode": "dynamic"
},
"egress_lossless_pool": {
"size": "12766208",
"type": "egress",
"mode": "static"
},
"egress_lossy_pool": {
"size": "7326924",
"type": "egress",
"mode": "dynamic"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"static_th":"12766208"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossy_pool]",
"size":"1518",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,53 @@
# name lanes alias index speed
Ethernet0 1 Ethernet0 1 1000
Ethernet1 2 Ethernet1 2 1000
Ethernet2 3 Ethernet2 3 1000
Ethernet3 4 Ethernet3 4 1000
Ethernet4 5 Ethernet4 5 1000
Ethernet5 6 Ethernet5 6 1000
Ethernet6 7 Ethernet6 7 1000
Ethernet7 8 Ethernet7 8 1000
Ethernet8 9 Ethernet8 9 1000
Ethernet9 10 Ethernet9 10 1000
Ethernet10 11 Ethernet10 11 1000
Ethernet11 12 Ethernet11 12 1000
Ethernet12 13 Ethernet12 13 1000
Ethernet13 14 Ethernet13 14 1000
Ethernet14 15 Ethernet14 15 1000
Ethernet15 16 Ethernet15 16 1000
Ethernet16 17 Ethernet16 17 1000
Ethernet17 18 Ethernet17 18 1000
Ethernet18 19 Ethernet18 19 1000
Ethernet19 20 Ethernet19 20 1000
Ethernet20 21 Ethernet20 21 1000
Ethernet21 22 Ethernet21 22 1000
Ethernet22 23 Ethernet22 23 1000
Ethernet23 24 Ethernet23 24 1000
Ethernet24 25 Ethernet24 25 1000
Ethernet25 26 Ethernet25 26 1000
Ethernet26 27 Ethernet26 27 1000
Ethernet27 28 Ethernet27 28 1000
Ethernet28 29 Ethernet28 29 1000
Ethernet29 30 Ethernet29 30 1000
Ethernet30 31 Ethernet30 31 1000
Ethernet31 32 Ethernet31 32 1000
Ethernet32 33 Ethernet32 33 1000
Ethernet33 34 Ethernet33 34 1000
Ethernet34 35 Ethernet34 35 1000
Ethernet35 36 Ethernet35 36 1000
Ethernet36 37 Ethernet36 37 1000
Ethernet37 38 Ethernet37 38 1000
Ethernet38 39 Ethernet38 39 1000
Ethernet39 40 Ethernet39 40 1000
Ethernet40 41 Ethernet40 41 1000
Ethernet41 42 Ethernet41 42 1000
Ethernet42 43 Ethernet42 43 1000
Ethernet43 44 Ethernet43 44 1000
Ethernet44 45 Ethernet44 45 1000
Ethernet45 46 Ethernet45 46 1000
Ethernet46 47 Ethernet46 47 1000
Ethernet47 48 Ethernet47 48 1000
Ethernet48 49 Ethernet48 49 10000
Ethernet49 50 Ethernet49 50 10000
Ethernet50 51 Ethernet50 51 10000
Ethernet51 52 Ethernet51 52 10000

View File

@ -0,0 +1,52 @@
# name lanes alias index speed
Ethernet0 1 Ethernet0 1 1000
Ethernet1 2 Ethernet1 2 1000
Ethernet2 3 Ethernet2 3 1000
Ethernet3 4 Ethernet3 4 1000
Ethernet4 5 Ethernet4 5 1000
Ethernet5 6 Ethernet5 6 1000
Ethernet6 7 Ethernet6 7 1000
Ethernet7 8 Ethernet7 8 1000
Ethernet8 9 Ethernet8 9 1000
Ethernet9 10 Ethernet9 10 1000
Ethernet10 11 Ethernet10 11 1000
Ethernet11 12 Ethernet11 12 1000
Ethernet12 13 Ethernet12 13 1000
Ethernet13 14 Ethernet13 14 1000
Ethernet14 15 Ethernet14 15 1000
Ethernet15 16 Ethernet15 16 1000
Ethernet16 17 Ethernet16 17 1000
Ethernet17 18 Ethernet17 18 1000
Ethernet18 19 Ethernet18 19 1000
Ethernet19 20 Ethernet19 20 1000
Ethernet20 21 Ethernet20 21 1000
Ethernet21 22 Ethernet21 22 1000
Ethernet22 23 Ethernet22 23 1000
Ethernet23 24 Ethernet23 24 1000
Ethernet24 25 Ethernet24 25 1000
Ethernet25 26 Ethernet25 26 1000
Ethernet26 27 Ethernet26 27 1000
Ethernet27 28 Ethernet27 28 1000
Ethernet28 29 Ethernet28 29 1000
Ethernet29 30 Ethernet29 30 1000
Ethernet30 31 Ethernet30 31 1000
Ethernet31 32 Ethernet31 32 1000
Ethernet32 33 Ethernet32 33 1000
Ethernet33 34 Ethernet33 34 1000
Ethernet34 35 Ethernet34 35 1000
Ethernet35 36 Ethernet35 36 1000
Ethernet36 37 Ethernet36 37 1000
Ethernet37 38 Ethernet37 38 1000
Ethernet38 39 Ethernet38 39 1000
Ethernet39 40 Ethernet39 40 1000
Ethernet40 41 Ethernet40 41 1000
Ethernet41 42 Ethernet41 42 1000
Ethernet42 43 Ethernet42 43 1000
Ethernet43 44 Ethernet43 44 1000
Ethernet44 45 Ethernet44 45 1000
Ethernet45 46 Ethernet45 46 1000
Ethernet46 47 Ethernet46 47 1000
Ethernet48 49 Ethernet48 49 10000
Ethernet49 50 Ethernet49 50 10000
Ethernet50 51 Ethernet50 51 10000
Ethernet51 52 Ethernet51 52 10000

View File

@ -0,0 +1,53 @@
# name lanes alias index speed
Ethernet0 1 Ethernet0 1 1000
Ethernet1 2 Ethernet1 2 1000
Ethernet2 3 Ethernet2 3 1000
Ethernet3 4 Ethernet3 4 1000
Ethernet4 5 Ethernet4 5 1000
Ethernet5 6 Ethernet5 6 1000
Ethernet6 7 Ethernet6 7 1000
Ethernet7 8 Ethernet7 8 1000
Ethernet8 9 Ethernet8 9 1000
Ethernet9 10 Ethernet9 10 1000
Ethernet10 11 Ethernet10 11 1000
Ethernet11 12 Ethernet11 12 1000
Ethernet12 13 Ethernet12 13 1000
Ethernet13 14 Ethernet13 14 1000
Ethernet14 15 Ethernet14 15 1000
Ethernet15 16 Ethernet15 16 1000
Ethernet16 17 Ethernet16 17 1000
Ethernet17 18 Ethernet17 18 1000
Ethernet18 19 Ethernet18 19 1000
Ethernet19 20 Ethernet19 20 1000
Ethernet20 21 Ethernet20 21 1000
Ethernet21 22 Ethernet21 22 1000
Ethernet22 23 Ethernet22 23 1000
Ethernet23 24 Ethernet23 24 1000
Ethernet24 25 Ethernet24 25 1000
Ethernet25 26 Ethernet25 26 1000
Ethernet26 27 Ethernet26 27 1000
Ethernet27 28 Ethernet27 28 1000
Ethernet28 29 Ethernet28 29 1000
Ethernet29 30 Ethernet29 30 1000
Ethernet30 31 Ethernet30 31 1000
Ethernet31 32 Ethernet31 32 1000
Ethernet32 33 Ethernet32 33 1000
Ethernet33 34 Ethernet33 34 1000
Ethernet34 35 Ethernet34 35 1000
Ethernet35 36 Ethernet35 36 1000
Ethernet36 37 Ethernet36 37 1000
Ethernet37 38 Ethernet37 38 1000
Ethernet38 39 Ethernet38 39 1000
Ethernet39 40 Ethernet39 40 1000
Ethernet40 41 Ethernet40 41 1000
Ethernet41 42 Ethernet41 42 1000
Ethernet42 43 Ethernet42 43 1000
Ethernet43 44 Ethernet43 44 1000
Ethernet44 45 Ethernet44 45 1000
Ethernet45 46 Ethernet45 46 1000
Ethernet46 47 Ethernet46 47 1000
Ethernet47 48 Ethernet47 48 1000
Ethernet48 49 Ethernet48 49 10000
Ethernet49 50 Ethernet49 50 10000
Ethernet50 51 Ethernet50 51 10000
Ethernet51 52 Ethernet51 52 10000

View File

@ -0,0 +1,2 @@
switchMacAddress=XX:XX:XX:XX:XX:XX
ledMode=ac3x97bits

View File

@ -0,0 +1,3 @@
switchMacAddress=XX:XX:XX:XX:XX:XX
inbandMgmtPortNum=48
ledMode=ac3x97bits

View File

@ -0,0 +1,2 @@
switchMacAddress=XX:XX:XX:XX:XX:XX
ledMode=ac3x97bits

View File

@ -0,0 +1,3 @@
mode=1
hwId=et6448m
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/profile.ini

View File

@ -0,0 +1 @@
Nokia-7215 l2

View File

@ -0,0 +1,10 @@
{
"chassis": {
"7215 IXS-T1": {
"component": {
"U-Boot": { },
"System-CPLD": { }
}
}
}
}

View File

@ -0,0 +1,14 @@
try:
import os
from sonic_eeprom import eeprom_tlvinfo
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0053/eeprom"
if not os.path.exists(self.eeprom_path):
os.system("echo 24c02 0x53 > /sys/class/i2c-adapter/i2c-0/new_device")
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,125 @@
#
# led_control.py
#
# Platform-specific LED control functionality for SONiC
#
try:
from sonic_led.led_control_base import LedControlBase
import os
import time
import syslog
import sonic_platform.platform
import sonic_platform.chassis
except ImportError as e:
raise ImportError(str(e) + " - required module not found")
smbus_present = 1
try:
import smbus
except ImportError as e:
smbus_present = 0
def DBG_PRINT(str):
syslog.openlog("nokia-led")
syslog.syslog(syslog.LOG_INFO, str)
syslog.closelog()
class LedControl(LedControlBase):
"""Platform specific LED control class"""
# Constructor
def __init__(self):
self.chassis = sonic_platform.platform.Platform().get_chassis()
self._initDefaultConfig()
def _initDefaultConfig(self):
# For the D1 box the port leds are controlled by Trident3 LED program
# The fan tray leds will be managed with the new thermalctl daemon / chassis class based API
# leaving only the system leds to be done old style
DBG_PRINT("starting system leds")
self._initSystemLed()
DBG_PRINT(" led done")
def _set_i2c_register(self, reg_file, value):
# On successful write, the value read will be written on
# reg_name and on failure returns 'ERR'
rv = 'ERR'
if (not os.path.isfile(reg_file)):
return rv
try:
with open(reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception as e:
rv = 'ERR'
return rv
def _initSystemLed(self):
# Front Panel System LEDs setting
oldfan = 0xf
oldpsu = 0xf
# Write sys led
if smbus_present == 0:
DBG_PRINT(" PMON LED SET ERROR -> smbus present = 0 ")
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICEREG = 0x7
bus.write_byte_data(DEVICE_ADDRESS, DEVICEREG, 0x02)
DBG_PRINT(" System LED set O.K. ")
while True:
# Front Panel FAN Panel LED setting in register 0x08
if (self.chassis.get_fan(0).get_status() == self.chassis.get_fan(1).get_status() == True):
if oldfan != 0x1:
if (os.path.isfile("/sys/class/gpio/fanLedAmber/value")):
self._set_i2c_register("/sys/class/gpio/fanLedAmber/value", 0)
self._set_i2c_register("/sys/class/gpio/fanLedGreen/value", 1)
oldfan = 0x1
else:
if oldfan != 0x0:
if (os.path.isfile("/sys/class/gpio/fanLedGreen/value")):
self._set_i2c_register("/sys/class/gpio/fanLedGreen/value", 0)
self._set_i2c_register("/sys/class/gpio/fanLedAmber/value", 1)
oldfan = 0x0
# Front Panel PSU Panel LED setting in register 0x09
if (self.chassis.get_psu(0).get_status() == self.chassis.get_psu(1).get_status() == True):
if oldpsu != 0x1:
if (os.path.isfile("/sys/class/gpio/psuLedAmber/value")):
self._set_i2c_register("/sys/class/gpio/psuLedAmber/value", 0)
self._set_i2c_register("/sys/class/gpio/psuLedGreen/value", 1)
oldpsu = 0x1
else:
if oldpsu != 0x0:
if (os.path.isfile("/sys/class/gpio/psuLedGreen/value")):
self._set_i2c_register("/sys/class/gpio/psuLedGreen/value", 0)
self._set_i2c_register("/sys/class/gpio/psuLedAmber/value", 1)
oldpsu = 0x0
time.sleep(6)
# Helper method to map SONiC port name to index
def _port_name_to_index(self, port_name):
# Strip "Ethernet" off port name
if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
return -1
port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
return port_idx
def _port_state_to_mode(self, port_idx, state):
DBG_PRINT("_port_state_to_mode")
def _port_led_mode_update(self, port_idx, ledMode):
DBG_PRINT("_port_led_mode_update")
# called when port states change- implementation of port_link_state_change() method if needed
def port_link_state_change(self, portname, state):
# DBG_PRINT("port_link_state_change ")
return

View File

@ -0,0 +1,32 @@
try:
import sonic_platform.platform
import sonic_platform.chassis
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
self.chassis = sonic_platform.platform.Platform().get_chassis()
def get_num_psus(self):
MAX_PSUS = 2
return MAX_PSUS
def get_psu_status(self, index):
# print " psuUtil redirect to PMON 2.0 "
if self.chassis is not None:
return self.chassis.get_psu(index-1).get_status()
else:
return False
def get_psu_presence(self, index):
# print " psuUtil redirect to PMON 2.0 "
if self.chassis is not None:
return self.chassis.get_psu(index-1).get_presence()
else:
return False

View File

@ -0,0 +1,65 @@
try:
import sonic_platform.platform
import sonic_platform.chassis
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class SfpUtil(SfpUtilBase):
"""Platform specific sfputil class"""
_port_start = 49
_port_end = 52
ports_in_block = 4
_port_to_eeprom_mapping = {}
_changed_ports = [0, 0, 0, 0]
@property
def port_start(self):
return self._port_start
@property
def port_end(self):
return self._port_end
@property
def qsfp_ports(self):
return range(0, 0)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
def __init__(self):
# print " SfpUtil(SfpUtilBase) re-directed to chassis PMON 2.0 "
SfpUtilBase.__init__(self)
self.chassis = sonic_platform.platform.Platform().get_chassis()
def reset(self, port_num):
# print " SfpUtil(SfpUtilBase) re-directed to chassis PMON 2.0 "
if self.chassis is not None:
return self.chassis.get_sfp(port_num).reset()
else:
return False
def set_low_power_mode(self, port_nuM, lpmode):
# print " SfpUtil(SfpUtilBase) targeted for deprecation "
return False
def get_low_power_mode(self, port_num):
# print " SfpUtil(SfpUtilBase) targeted for deprecation "
return False
def get_presence(self, port_num):
# print " SfpUtil(SfpUtilBase) re-directed to chassis PMON 2.0 "
if self.chassis is not None:
return self.chassis.get_sfp(port_num).get_presence()
else:
return False
def get_transceiver_change_event(self, timeout):
# print " SfpUtil(SfpUtilBase) targeted for deprecation "
raise NotImplementedError

View File

@ -0,0 +1,19 @@
chip "adt7473-*"
label fan1 "rear fan 1"
label fan2 "rear fan 2"
ignore fan3
ignore fan4
ignore in1
chip "lm75a-i2c-*-4a"
label temp1 "MAC temp sensor"
set temp1_max 65
set temp1_crit 75
chip "lm75a-i2c-*-4b"
label temp1 "Board temp sensor"
set temp2_max 65
set temp2_crit 75
chip "armada_thermal-*"
ignore temp1

View File

@ -0,0 +1,65 @@
{
"thermal_control_algorithm": {
"run_at_boot_up": "false",
"fan_speed_when_suspend": "50"
},
"info_types": [
{
"type": "fan_info"
},
{
"type": "thermal_info"
},
{
"type": "chassis_info"
}
],
"policies": [
{
"name": "any fan absence",
"conditions": [
{
"type": "fan.any.absence"
}
],
"actions": [
{
"type": "thermal_control.control",
"status": "false"
},
{
"type": "fan.all.set_speed",
"speed": "100"
}
]
},
{
"name": "all fan presence",
"conditions": [
{
"type": "fan.all.presence"
}
],
"actions": [
{
"type": "thermal.temp_check_and_set_all_fan_speed",
"default_speed": "50",
"hightemp_speed": "100"
}
]
},
{
"name": "temp over high critical threshold",
"conditions": [
{
"type": "thermal.over.high_critical_threshold"
}
],
"actions": [
{
"type": "switch.shutdown"
}
]
}
]
}

View File

@ -5,7 +5,8 @@ $(SONIC_ONE_IMAGE)_MACHINE = marvell-armhf
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_INSTALLS += $(LINUX_KERNEL_DTB)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(ET6448M_PLATFORM)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(ET6448M_PLATFORM) \
$(NOKIA_7215_PLATFORM)
ifeq ($(INSTALL_DEBUG_TOOLS),y)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES)
$(SONIC_ONE_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES))

View File

@ -0,0 +1,11 @@
# Nokia Platform
NOKIA_7215_PLATFORM_VERSION = 1.0
export NOKIA_7215_PLATFORM_VERSION
NOKIA_7215_PLATFORM = sonic-platform-nokia-7215_$(NOKIA_7215_PLATFORM_VERSION)_$(CONFIGURED_ARCH).deb
$(NOKIA_7215_PLATFORM)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-nokia
$(NOKIA_7215_PLATFORM)_PLATFORM = armhf-nokia_ixs7215_52x-r0
SONIC_DPKG_DEBS += $(NOKIA_7215_PLATFORM)
SONIC_STRETCH_DEBS += $(NOKIA_7215_PLATFORM)

View File

@ -100,7 +100,11 @@ prepare_boot_menu() {
fw_setenv ${FW_ARG} sonic_version_2 $sonic_version_2 > /dev/null
BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";echo;'
BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";echo;'
if [ "$PLATFORM" = "armhf-nokia_ixs7215_52x-r0" ]; then
BOOT3='echo " > Boot3: ONIE - run onie_bootcmd";echo;'
else
BOOT3='echo " > Boot3: ONIE - run onie_nand_boot";echo;'
fi
BORDER='echo "---------------------------------------------------";echo;'
fw_setenv ${FW_ARG} print_menu $BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER > /dev/null

View File

@ -8,6 +8,7 @@ include $(PLATFORM_PATH)/docker-ptf-mrvl.mk
include $(PLATFORM_PATH)/one-image.mk
include $(PLATFORM_PATH)/linux-kernel-armhf.mk
include $(PLATFORM_PATH)/platform-et6448m.mk
include $(PLATFORM_PATH)/platform-nokia.mk
INCLUDE_SYSTEM_TELEMETRY = ""
ENABLE_SYNCD_RPC = ""

View File

@ -0,0 +1,61 @@
#!/bin/bash
# Platform init script for Nokia IXS 7215
# Load required kernel-mode drivers
load_kernel_drivers() {
# Remove modules loaded during Linux init
# FIX-ME: This will be removed in the future when Linux init no longer loads these
rmmod i2c_mux_gpio
rmmod i2c_dev
rmmod i2c_mv64xxx
# Carefully control the load order here to ensure consistent i2c bus numbering
modprobe i2c_mv64xxx
modprobe i2c_dev
modprobe i2c_mux_gpio
modprobe eeprom
}
nokia_7215_profile()
{
MAC_ADDR=$(sudo decode-syseeprom -m)
sed -i "s/switchMacAddress=.*/switchMacAddress=$MAC_ADDR/g" /usr/share/sonic/device/armhf-nokia_ixs7215_52x-r0/Nokia-7215/profile.ini
echo "Nokia-7215: Updating switch mac address ${MAC_ADDR}"
}
# - Main entry
# Install kernel drivers required for i2c bus access
load_kernel_drivers
# LOGIC to enumerate SFP eeprom devices - send 0x50 to kernel i2c driver - initialize devices
# the mux may be enumerated at number 4 or 5 so we check for the mux and skip if needed
# Get list of the mux channels
ismux_bus=$(i2cdetect -l|grep mux|cut -f1)
# Enumerate the SFP eeprom device on each mux channel
for mux in ${ismux_bus}
do
echo optoe2 0x50 > /sys/class/i2c-adapter/${mux}/new_device
done
# Enumerate system eeprom
echo 24c02 0x53 > /sys/class/i2c-adapter/i2c-0/new_device
sleep 2
chmod 644 /sys/class/i2c-adapter/i2c-0/0-0053/eeprom
# Enumerate fan eeprom devices
echo eeprom 0x55 > /sys/class/i2c-adapter/i2c-0/new_device
echo eeprom 0x56 > /sys/class/i2c-adapter/i2c-0/new_device
# Enable optical SFP Tx
i2cset -y -m 0x0f 0 0x41 0x5 0x00
# Ensure switch is programmed with chassis base MAC addr
nokia_7215_profile
echo "Nokia-7215 - completed platform init script"
exit 0

View File

@ -0,0 +1,14 @@
[Unit]
Description=Nokia-7215 Platform Service
Before=pmon.service
After=sysinit.target
DefaultDependencies=no
[Service]
ExecStart=/usr/local/bin/nokia-7215init.sh
KillSignal=SIGKILL
SuccessExitStatus=SIGKILL
#StandardOutput=tty
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
from setuptools import setup
os.listdir
setup(
name='sonic_platform',
version='1.0',
description='Module to initialize Nokia IXS 7215 platforms',
packages=['sonic_platform','sonic_platform.test'],
package_dir={'sonic_platform': '7215/sonic_platform'},
)

View File

@ -0,0 +1,377 @@
#############################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import os
import sys
import glob
from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.sfp import Sfp
from sonic_platform.eeprom import Eeprom
from sonic_platform.fan import Fan
from .fan_drawer import VirtualDrawer
from sonic_platform.psu import Psu
from sonic_platform.thermal import Thermal
from sonic_platform.component import Component
from sonic_py_common import logger
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
smbus_present = 1
try:
import smbus
except ImportError as e:
smbus_present = 0
MAX_SELECT_DELAY = 3600
COPPER_PORT_START = 1
COPPER_PORT_END = 48
SFP_PORT_START = 49
SFP_PORT_END = 52
PORT_END = 52
# Device counts
MAX_7215_FAN_DRAWER = 1
MAX_7215_FAN = 2
MAX_7215_PSU = 2
MAX_7215_THERMAL = 6
# Temp - disable these to help with early debug
MAX_7215_COMPONENT = 2
SYSLOG_IDENTIFIER = "chassis"
sonic_logger = logger.Logger(SYSLOG_IDENTIFIER)
class Chassis(ChassisBase):
"""
Nokia platform-specific Chassis class
Derived from Dell S6000 platform.
customized for the 7215 platform.
"""
def __init__(self):
ChassisBase.__init__(self)
self.system_led_supported_color = ['off', 'amber', 'green', 'amber_blink', 'green_blink']
# Port numbers for SFP List Initialization
self.COPPER_PORT_START = COPPER_PORT_START
self.COPPER_PORT_END = COPPER_PORT_END
self.SFP_PORT_START = SFP_PORT_START
self.SFP_PORT_END = SFP_PORT_END
self.PORT_END = PORT_END
# for non-sfp ports create dummy objects for copper / non-sfp ports
for index in range(self.COPPER_PORT_START, self.COPPER_PORT_END+1):
sfp_node = Sfp(index, 'COPPER', 'N/A', 'N/A')
self._sfp_list.append(sfp_node)
# Verify optoe2 driver SFP eeprom devices were enumerated and exist
# then create the sfp nodes
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
mux_dev = sorted(glob.glob("/sys/class/i2c-adapter/i2c-0/i2c-[0-9]"))
y = 0
for index in range(self.SFP_PORT_START, self.SFP_PORT_END+1):
mux_dev_num = mux_dev[y]
port_i2c_map = mux_dev_num[-1]
y = y + 1
port_eeprom_path = eeprom_path.format(port_i2c_map)
if not os.path.exists(port_eeprom_path):
sonic_logger.log_info("path %s didnt exist" % port_eeprom_path)
sfp_node = Sfp(index, 'SFP', port_eeprom_path, port_i2c_map)
self._sfp_list.append(sfp_node)
self.sfp_event_initialized = False
# Instantiate system eeprom object
self._eeprom = Eeprom()
# Construct lists fans, power supplies, thermals & components
drawer_num = MAX_7215_FAN_DRAWER
fan_num_per_drawer = MAX_7215_FAN
drawer_ctor = VirtualDrawer
fan_index = 0
for drawer_index in range(drawer_num):
drawer = drawer_ctor(drawer_index)
self._fan_drawer_list.append(drawer)
for index in range(fan_num_per_drawer):
fan = Fan(fan_index, drawer)
fan_index += 1
drawer._fan_list.append(fan)
self._fan_list.append(fan)
for i in range(MAX_7215_PSU):
psu = Psu(i)
self._psu_list.append(psu)
for i in range(MAX_7215_THERMAL):
thermal = Thermal(i)
self._thermal_list.append(thermal)
for i in range(MAX_7215_COMPONENT):
component = Component(i)
self._component_list.append(component)
def get_sfp(self, index):
"""
Retrieves sfp represented by (1-based) index <index>
Args:
index: An integer, the index (1-based) of the sfp to retrieve.
The index should be the sequence of physical SFP ports in a
chassis starting from 1.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
try:
# The index will start from 1
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_name(self):
"""
Retrieves the name of the chassis
Returns:
string: The name of the chassis
"""
return self._eeprom.modelstr()
def get_presence(self):
"""
Retrieves the presence of the chassis
Returns:
bool: True if chassis is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the chassis
Returns:
string: Model/part number of chassis
"""
return self._eeprom.part_number_str()
def get_serial(self):
"""
Retrieves the serial number of the chassis (Service tag)
Returns:
string: Serial number of chassis
"""
return self._eeprom.serial_str()
def get_status(self):
"""
Retrieves the operational status of the chassis
Returns:
bool: A boolean value, True if chassis is operating properly
False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.base_mac_addr()
def get_serial_number(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this
chassis.
"""
return self._eeprom.serial_number_str()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the
chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their
corresponding values.
"""
return self._eeprom.system_eeprom_info()
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
# The ixs7215 CPLD does not have a hardware reboot cause register so
# the hardware portion of reboot cause can't be implemented
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None)
def get_change_event(self, timeout=0):
"""
Returns a nested dictionary containing all devices which have
experienced a change at chassis level
Args:
timeout: Timeout in milliseconds (optional). If timeout == 0,
this method will block until a change is detected.
Returns:
(bool, dict):
- True if call successful, False if not;
- A nested dictionary where key is a device type,
value is a dictionary with key:value pairs in the format of
{'device_id':'device_event'},
where device_id is the device ID for this device and
device_event,
status='1' represents device inserted,
status='0' represents device removed.
Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}}
indicates that fan 0 has been removed, fan 2
has been inserted and sfp 11 has been removed.
"""
# Initialize SFP event first
if not self.sfp_event_initialized:
from sonic_platform.sfp_event import sfp_event
self.sfp_event = sfp_event()
self.sfp_event.initialize()
self.MAX_SELECT_EVENT_RETURNED = self.PORT_END
self.sfp_event_initialized = True
wait_for_ever = (timeout == 0)
port_dict = {}
if wait_for_ever:
# xrcvd will call this monitor loop in the "SYSTEM_READY" state
timeout = MAX_SELECT_DELAY
while True:
status = self.sfp_event.check_sfp_status(port_dict, timeout)
if not port_dict == {}:
break
else:
# At boot up and in "INIT" state call from xrcvd will have timeout
# value return true without change after timeout and will
# transition to "SYSTEM_READY"
status = self.sfp_event.check_sfp_status(port_dict, timeout)
if status:
return True, {'sfp': port_dict}
else:
return True, {'sfp': {}}
def get_thermal_manager(self):
from .thermal_manager import ThermalManager
return ThermalManager
def set_status_led(self, color):
"""
Sets the state of the system LED
Args:
color: A string representing the color with which to set the
system LED
Returns:
bool: True if system LED state is set successfully, False if not
"""
if color not in self.system_led_supported_color:
return False
if (color == 'off'):
value = 0x00
elif (color == 'amber'):
value = 0x01
elif (color == 'green'):
value = 0x02
elif (color == 'amber_blink'):
value = 0x03
elif (color == 'green_blink'):
value = 0x04
else:
return False
# Write sys led
if smbus_present == 0:
sonic_logger.log_info("PMON LED SET ERROR-> smbus present = 0")
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICEREG = 0x7
bus.write_byte_data(DEVICE_ADDRESS, DEVICEREG, value)
sonic_logger.log_info(" System LED set O.K. ")
return True
return False
def get_status_led(self):
"""
Gets the state of the system LED
Returns:
A string, one of the valid LED color strings which could be vendor
specified.
"""
# Read sys led
if smbus_present == 0:
sonic_logger.log_info("PMON LED GET ERROR-> smbus present = 0")
return False
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x7
value = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if value == 0x00:
color = 'off'
elif value == 0x01:
color = 'amber'
elif value == 0x02:
color = 'green'
elif value == 0x03:
color = 'amber_blink'
elif value == 0x04:
color = 'green_blink'
else:
return False
return color
def get_watchdog(self):
"""
Retrieves hardware watchdog device on this chassis
Returns:
An object derived from WatchdogBase representing the hardware
watchdog device
Note:
We overload this method to ensure that watchdog is only initialized
when it is referenced. Currently, only one daemon can open the
watchdog. To initialize watchdog in the constructor causes multiple
daemon try opening watchdog when loading and constructing a chassis
object and fail. By doing so we can eliminate that risk.
"""
try:
if self._watchdog is None:
from sonic_platform.watchdog import WatchdogImplBase
watchdog_device_path = "/dev/watchdog0"
self._watchdog = WatchdogImplBase(watchdog_device_path)
except Exception as e:
sonic_logger.log_info("Fail to load watchdog {}".format(repr(e)))
return self._watchdog

View File

@ -0,0 +1,119 @@
########################################################################
# NOKIA IXS7215
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in
# the platform
#
########################################################################
try:
import os
import sys
import subprocess
import ntpath
from sonic_platform_base.component_base import ComponentBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
try:
import smbus
except ImportError as e:
smbus_present = 0
if sys.version_info[0] < 3:
import commands as cmd
else:
import subprocess as cmd
class Component(ComponentBase):
"""Nokia platform-specific Component class"""
CHASSIS_COMPONENTS = [
["System-CPLD", "Used for managing SFPs, LEDs, PSUs and FANs "],
["U-Boot", "Performs initialization during booting"],
]
def __init__(self, component_index):
self.index = component_index
self.name = self.CHASSIS_COMPONENTS[self.index][0]
self.description = self.CHASSIS_COMPONENTS[self.index][1]
def _get_command_result(self, cmdline):
try:
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
result = stdout.rstrip('\n')
except OSError:
result = None
return result
def _get_cpld_version(self, cpld_number):
if smbus_present == 0:
cmdstatus, cpld_version = cmd.getstatusoutput('i2cget -y 0 0x41 0x2')
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x2
cpld_version = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
return str(int(cpld_version, 16))
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return self.name
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return self.description
def get_firmware_version(self):
"""
Retrieves the firmware version of the component
Returns:
A string containing the firmware version of the component
"""
if self.index == 0:
return self._get_cpld_version(self.index)
if self.index == 1:
cmdstatus, uboot_version = cmd.getstatusoutput('grep --null-data U-Boot /dev/mtd0ro|head -1 | cut -c 1-30')
return uboot_version
def install_firmware(self, image_path):
"""
Installs firmware to the component
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install was successful, False if not
"""
image_name = ntpath.basename(image_path)
print(" ixs7215 - install cpld {}".format(image_name))
# check whether the image file exists
if not os.path.isfile(image_path):
print("ERROR: the cpld image {} doesn't exist ".format(image_path))
return False
success_flag = False
return success_flag

View File

@ -0,0 +1,235 @@
########################################################################
# Nokia IXR7220_D1
#
# Module contains platform specific implementation of SONiC Platform
# Base API and provides the EEPROMs' information.
#
# The different EEPROMs available are as follows:
# - System EEPROM : Contains Serial number, Service tag, Base MA
# address, etc. in ONIE TlvInfo EEPROM format.
# - PSU EEPROM : Contains Serial number, Part number, Service Tag,
# PSU type, Revision.
# - Fan EEPROM : Contains Serial number, Part number, Service Tag,
# Fan type, Number of Fans in Fantray, Revision.
########################################################################
try:
from sonic_platform_base.sonic_eeprom.eeprom_base import EepromDecoder
from sonic_platform_base.sonic_eeprom.eeprom_tlvinfo import TlvInfoDecoder
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
# PSU eeprom fields in format required by EepromDecoder
psu_eeprom_format = [
('PPID', 's', 20), ('DPN Rev', 's', 3), ('Service Tag', 's', 7),
('Part Number', 's', 10), ('Part Num Revision', 's', 3),
('Mfg Test', 's', 2), ('Redundant copy', 's', 83), ('PSU Type', 's', 1),
('Fab Rev', 's', 2)
]
# Fan eeprom fields in format required by EepromDecoder
fan_eeprom_format = [
('Model', 's', 12), ('Serial Number', 's', 13)
]
class Eeprom(TlvInfoDecoder):
"""Nokia platform-specific EEPROM class"""
I2C_DIR = "/sys/class/i2c-adapter/"
def __init__(self, is_psu=False, psu_index=0, is_fan=False, fan_index=0):
self.is_psu_eeprom = is_psu
self.is_fan_eeprom = is_fan
self.is_sys_eeprom = not (is_psu | is_fan)
if self.is_sys_eeprom:
self.start_offset = 0
self.eeprom_path = self.I2C_DIR + "i2c-0/0-0053/eeprom"
# System EEPROM is in ONIE TlvInfo EEPROM format
super(Eeprom, self).__init__(self.eeprom_path,
self.start_offset, '', True)
self._load_system_eeprom()
else:
if self.is_psu_eeprom:
self.index = psu_index
self.start_offset = 6
self.eeprom_path = self.I2C_DIR \
+ "i2c-1/1-005{}/eeprom".format(2 - self.index)
self.format = psu_eeprom_format
else:
self.index = fan_index
self.start_offset = 13
self.eeprom_path = self.I2C_DIR \
+ "i2c-4{0}/4{0}-0050/eeprom".format(self.index - 1)
self.format = fan_eeprom_format
EepromDecoder.__init__(self, self.eeprom_path, self.format,
self.start_offset, '', True)
self._load_device_eeprom()
def _load_system_eeprom(self):
"""
Reads the system EEPROM and retrieves the values corresponding
to the codes defined as per ONIE TlvInfo EEPROM format and fills
them in a dictionary.
"""
try:
# Read System EEPROM as per ONIE TlvInfo EEPROM format.
self.eeprom_data = self.read_eeprom()
except Exception as e:
self.base_mac = 'NA'
self.serial_number = 'NA'
self.part_number = 'NA'
self.model_str = 'NA'
self.serial = 'NA'
self.eeprom_tlv_dict = dict()
else:
eeprom = self.eeprom_data
self.eeprom_tlv_dict = dict()
if not self.is_valid_tlvinfo_header(eeprom):
self.base_mac = 'NA'
self.serial_number = 'NA'
self.part_number = 'NA'
self.model_str = 'NA'
self.serial = 'NA'
return
total_length = (ord(eeprom[9]) << 8) | ord(eeprom[10])
tlv_index = self._TLV_INFO_HDR_LEN
tlv_end = self._TLV_INFO_HDR_LEN + total_length
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
if not self.is_valid_tlv(eeprom[tlv_index:]):
break
tlv = eeprom[tlv_index:tlv_index + 2
+ ord(eeprom[tlv_index + 1])]
code = "0x%02X" % (ord(tlv[0]))
if ord(tlv[0]) == self._TLV_CODE_VENDOR_EXT:
value = str((ord(tlv[2]) << 24) | (ord(tlv[3]) << 16) |
(ord(tlv[4]) << 8) | ord(tlv[5]))
value += str(tlv[6:6 + ord(tlv[1])])
else:
name, value = self.decoder(None, tlv)
self.eeprom_tlv_dict[code] = value
if ord(eeprom[tlv_index]) == self._TLV_CODE_CRC_32:
break
tlv_index += ord(eeprom[tlv_index+1]) + 2
self.base_mac = self.eeprom_tlv_dict.get(
"0x%X" % (self._TLV_CODE_MAC_BASE), 'NA')
self.serial_number = self.eeprom_tlv_dict.get(
"0x%X" % (self._TLV_CODE_SERIAL_NUMBER), 'NA')
self.part_number = self.eeprom_tlv_dict.get(
"0x%X" % (self._TLV_CODE_PART_NUMBER), 'NA')
self.model_str = self.eeprom_tlv_dict.get(
"0x%X" % (self._TLV_CODE_PRODUCT_NAME), 'NA')
self.serial = self.eeprom_tlv_dict.get(
"0x%X" % (self._TLV_CODE_SERVICE_TAG), 'NA')
def _load_device_eeprom(self):
"""
Reads the Fan/PSU EEPROM and retrieves the serial number and
model number of the device.
"""
try:
# Read Fan/PSU EEPROM as per the specified format.
self.eeprom_data = EepromDecoder.read_eeprom(self)
except Exception as e:
self.serial_number = 'NA'
self.part_number = 'NA'
self.model_str = 'NA'
self.serial = 'NA'
else:
(valid, data) = self._get_eeprom_field("Model")
if valid:
self.model_str = data
else:
self.model_str = 'NA'
(valid, data) = self._get_eeprom_field("Serial Number")
if valid:
self.serial_number = data
else:
self.serial_number = 'NA'
if self.is_psu_eeprom:
(valid, data) = self._get_eeprom_field("PSU Type")
if valid:
self.psu_type = data
else:
self.psu_type = 'NA'
else:
(valid, data) = self._get_eeprom_field("Fan Type")
if valid:
self.fan_type = data
else:
self.fan_type = 'NA'
def _get_eeprom_field(self, field_name):
"""
For a field name specified in the EEPROM format, returns the
presence of the field and the value for the same.
"""
field_start = 0
for field in self.format:
field_end = field_start + field[2]
if field[0] == field_name:
return (True, self.eeprom_data[field_start:field_end])
field_start = field_end
return (False, None)
def serial_number_str(self):
"""
Returns the serial number.
"""
return self.serial_number
def part_number_str(self):
"""
Returns the part number.
"""
return self.part_number
def airflow_fan_type(self):
"""
Returns the airflow fan type.
"""
if self.is_psu_eeprom:
return int(self.psu_type.encode('hex'), 16)
else:
return int(self.fan_type.encode('hex'), 16)
# System EEPROM specific methods
def base_mac_addr(self):
"""
Returns the base MAC address found in the system EEPROM.
"""
return self.base_mac
def modelstr(self):
"""
Returns the Model name.
"""
return self.model_str
def serial_str(self):
"""
Returns the servicetag number.
"""
return self.serial
def system_eeprom_info(self):
"""
Returns a dictionary, where keys are the type code defined in
ONIE EEPROM format and values are their corresponding values
found in the system EEPROM.
"""
return self.eeprom_tlv_dict

View File

@ -0,0 +1,330 @@
########################################################################
# Nokia 7215
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fans' information which are available in the platform
#
########################################################################
try:
import os
from sonic_platform_base.fan_base import FanBase
from sonic_py_common import logger
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
smbus_present = 1
try:
import smbus
except ImportError as e:
smbus_present = 0
MAX_IXS7215_FAN_SPEED = 19000
WORKING_IXS7215_FAN_SPEED = 960
sonic_logger = logger.Logger('fan')
class Fan(FanBase):
"""Nokia platform-specific Fan class"""
def __init__(self, fan_index, fan_drawer, psu_fan=False, dependency=None):
self.is_psu_fan = psu_fan
ADT7473_DIR = "/sys/bus/i2c/devices/0-002e/"
if not self.is_psu_fan:
# Fan is 1-based in Nokia platforms
self.index = fan_index + 1
self.fan_drawer = fan_drawer
self.set_fan_speed_reg = ADT7473_DIR+"pwm{}".format(self.index)
self.get_fan_speed_reg = ADT7473_DIR+"fan{}_input".format(self.index)
self.max_fan_speed = MAX_IXS7215_FAN_SPEED
self.supported_led_color = ['off', 'green', 'red']
else:
# this is a PSU Fan
self.index = fan_index
self.dependency = dependency
def _get_i2c_register(self, reg_file):
# On successful read, returns the value read from given
# reg_name and on failure returns 'ERR'
rv = 'ERR'
if (not os.path.isfile(reg_file)):
return rv
try:
with open(reg_file, 'r') as fd:
rv = fd.read()
except Exception as e:
rv = 'ERR'
rv = rv.rstrip('\r\n')
rv = rv.lstrip(" ")
return rv
def _set_i2c_register(self, reg_file, value):
# On successful write, the value read will be written on
# reg_name and on failure returns 'ERR'
rv = 'ERR'
if (not os.path.isfile(reg_file)):
return rv
try:
with open(reg_file, 'w') as fd:
rv = fd.write(str(value))
except Exception as e:
rv = 'ERR'
return rv
def get_name(self):
"""
Retrieves the name of the Fan
Returns:
string: The name of the Fan
"""
if not self.is_psu_fan:
return "Fan{}".format(self.index)
else:
return "PSU{} Fan".format(self.index)
def get_presence(self):
"""
Retrieves the presence of the Fan Unit
Returns:
bool: True if Fan is present, False if not
"""
if smbus_present == 0:
sonic_logger.log_info("PMON fan-smbus ERROR - presence ")
return False
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0xb
fanstatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if self.index == 1:
fanstatus = fanstatus & 1
if fanstatus == 1:
return False
if self.index == 2:
fanstatus = fanstatus & 2
if fanstatus == 2:
return False
return True
def get_model(self):
"""
Retrieves the model number of the Fan
Returns:
string: Part number of Fan
"""
return 'NA'
def get_serial(self):
"""
Retrieves the serial number of the Fan
Returns:
string: Serial number of Fan
"""
return 'NA'
def get_status(self):
"""
Retrieves the operational status of the Fan
Returns:
bool: True if Fan is operating properly, False if not
"""
status = False
fan_speed = self._get_i2c_register(self.get_fan_speed_reg)
if (fan_speed != 'ERR'):
if (int(fan_speed) > WORKING_IXS7215_FAN_SPEED):
status = True
return status
def get_direction(self):
"""
Retrieves the fan airflow direction
Possible fan directions (relative to port-side of device)
Returns:
A string, either FAN_DIRECTION_INTAKE or
FAN_DIRECTION_EXHAUST depending on fan direction
"""
return 'FAN_DIRECTION_INTAKE'
def get_speed(self):
"""
Retrieves the speed of a Front FAN in the tray in revolutions per
minute defined by 1-based index
:param index: An integer, 1-based index of the FAN to query speed
:return: integer, denoting front FAN speed
"""
speed = 0
fan_speed = self._get_i2c_register(self.get_fan_speed_reg)
if (fan_speed != 'ERR'):
speed = int(fan_speed)
else:
speed = 0
return speed
def get_speed_tolerance(self):
"""
Retrieves the speed tolerance of the fan
Returns:
An integer, the percentage of variance from target speed
which is considered tolerable
"""
if self.get_presence():
# The tolerance value is fixed as 25% for this platform
tolerance = 25
else:
tolerance = 0
return tolerance
def set_speed(self, speed):
"""
Set fan speed to expected value
Args:
speed: An integer, the percentage of full fan speed to set
fan to, in the range 0 (off) to 100 (full speed)
Returns:
bool: True if set success, False if fail.
"""
if self.is_psu_fan:
return False
# Set current fan duty cycle
# - 0x00 : fan off
# - 0x40 : 25% duty cycle
# - 0x80 : 50% duty cycle (default)
# - 0xff : 100% duty cycle (full speed)
if speed in range(0, 6):
fandutycycle = 0x00
elif speed in range(6, 41):
fandutycycle = 64
elif speed in range(41, 76):
fandutycycle = 128
elif speed in range(76, 101):
fandutycycle = 255
else:
return False
rv = self._set_i2c_register(self.set_fan_speed_reg, fandutycycle)
if (rv != 'ERR'):
return True
else:
return False
def set_status_led(self, color):
"""
Set led to expected color
Args:
color: A string representing the color with which to set the
fan module status LED
Returns:
bool: True if set success, False if fail.
off , red and green are the only settings 7215 fans
"""
if self.is_psu_fan or (color not in self.supported_led_color):
return False
if (color == self.STATUS_LED_COLOR_AMBER):
return False
if (color == self.STATUS_LED_COLOR_RED):
value = 0x02
elif (color == self.STATUS_LED_COLOR_GREEN):
value = 0x01
elif (color == self.STATUS_LED_COLOR_OFF):
value = 0x00
else:
return False
if smbus_present == 0:
return False
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICEREG = 0x8
original = bus.read_byte_data(DEVICE_ADDRESS, DEVICEREG)
if (self.index == 1):
new = value << 4
ledstatus = original & 0xcf
ledstatus = ledstatus | new
elif self.index == 2:
new = value << 6
ledstatus = original & 0x3f
ledstatus = ledstatus | new
else:
return False
bus.write_byte_data(DEVICE_ADDRESS, DEVICEREG, ledstatus)
return True
def get_status_led(self):
"""
Gets the state of the fan status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings.
"""
if self.is_psu_fan:
return False
if smbus_present == 0:
return False
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x8
ledstatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if self.index == 1:
ledstatus = (ledstatus & 0x30)
ledstatus = ledstatus >> 4
elif self.index == 2:
ledstatus = (ledstatus & 0xC0)
ledstatus = ledstatus >> 6
if ledstatus == 0x02:
return self.STATUS_LED_COLOR_RED
elif ledstatus == 0x1:
return self.STATUS_LED_COLOR_GREEN
else:
return self.STATUS_LED_COLOR_OFF
def get_target_speed(self):
"""
Retrieves the target (expected) speed of the fan
Returns:
An integer, the percentage of full fan speed, in the range 0
(off) to 100 (full speed)
"""
speed = 0
fan_speed = self._get_i2c_register(self.get_fan_speed_reg)
if (fan_speed != 'ERR'):
speed = int(fan_speed)
else:
speed = 0
return speed

View File

@ -0,0 +1,47 @@
#############################################################################
# Nokia
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan Drawer status which is available in the platform
#
#############################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class NokiaFanDrawer(FanDrawerBase):
def __init__(self, index):
super(NokiaFanDrawer, self).__init__()
self._index = index + 1
self._led = None
def get_index(self):
return self._index
def get_led(self):
return self._led
# For Nokia platforms with fan drawer(s)
class RealDrawer(NokiaFanDrawer):
def __init__(self, index):
super(RealDrawer, self).__init__(index)
self._name = 'drawer{}'.format(self._index)
def get_name(self):
return self._name
# For Nokia platforms with no physical fan drawer(s)
class VirtualDrawer(NokiaFanDrawer):
def __init__(self, index):
super(VirtualDrawer, self).__init__(index)
def get_name(self):
return 'N/A'
def set_status_led(self, color):
return 'N/A'

View File

@ -0,0 +1,22 @@
#############################################################################
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""
Nokia platform-specific class
"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,225 @@
########################################################################
# Nokia 7215
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs' information which are available in the platform
#
########################################################################
try:
import sys
from sonic_platform_base.psu_base import PsuBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
if sys.version_info[0] < 3:
import commands as cmd
else:
import subprocess as cmd
smbus_present = 1
try:
import smbus
except ImportError as e:
smbus_present = 0
class Psu(PsuBase):
"""Nokia platform-specific PSU class for 7215 """
def __init__(self, psu_index):
# PSU is 1-based in Nokia platforms
self.index = psu_index + 1
self._fan_list = []
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return "PSU{}".format(self.index)
def get_presence(self):
"""
Retrieves the presence of the Power Supply Unit (PSU)
Returns:
bool: True if PSU is present, False if not
"""
if smbus_present == 0: # if called from psuutil outside of pmon
cmdstatus, psustatus = cmd.getstatusoutput('i2cget -y 0 0x41 0xa')
psustatus = int(psustatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0xa
psustatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if self.index == 1:
psustatus = psustatus & 1
if psustatus == 1:
return False
if self.index == 2:
psustatus = psustatus & 2
if psustatus == 2:
return False
return True
def get_model(self):
"""
Retrieves the part number of the PSU
Returns:
string: Part number of PSU
"""
return self.eeprom.modelstr()
def get_serial(self):
"""
Retrieves the serial number of the PSU
Returns:
string: Serial number of PSU
"""
return self.eeprom.serial_number_str()
def get_status(self):
"""
Retrieves the operational status of the PSU
Returns:
bool: True if PSU is operating properly, False if not
"""
if smbus_present == 0:
cmdstatus, psustatus = cmd.getstatusoutput('i2cget -y 0 0x41 0xa')
psustatus = int(psustatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0xa
psustatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if self.index == 1:
psustatus = psustatus & 4
if psustatus == 4:
return True
if self.index == 2:
psustatus = psustatus & 8
if psustatus == 8:
return True
return False
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
if smbus_present == 0:
cmdstatus, psustatus = cmd.getstatusoutput('i2cget -y 0 0x41 0xa')
psustatus = int(psustatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0xa
psustatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if self.index == 1:
psustatus = psustatus & 4
if psustatus == 4:
psu_voltage = 12.0
return psu_voltage
if self.index == 2:
psustatus = psustatus & 8
if psustatus == 8:
psu_voltage = 12.0
return psu_voltage
psu_voltage = 0.0
return psu_voltage
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, electric current in amperes,
e.g. 15.4
"""
psu_current = 0.0
return psu_current
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts,
e.g. 302.6
"""
psu_power = 0.0
return psu_power
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and
passed all its internal self-tests, False if not.
"""
if smbus_present == 0:
cmdstatus, psustatus = cmd.getstatusoutput('i2cget -y 0 0x41 0xa')
psustatus = int(psustatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0xa
psustatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
if self.index == 1:
psustatus = psustatus & 4
if psustatus == 4:
return True
if self.index == 2:
psustatus = psustatus & 8
if psustatus == 8:
return True
return False
def get_status_led(self):
"""
Gets the state of the PSU status LED
Returns:
A string, one of the predefined STATUS_LED_COLOR_* strings.
"""
if self.get_powergood_status():
return self.STATUS_LED_COLOR_GREEN
else:
return self.STATUS_LED_COLOR_OFF
def set_status_led(self, color):
"""
Sets the state of the PSU status LED
Args:
color: A string representing the color with which to set the
PSU status LED
Returns:
bool: True if status LED state is set successfully, False if
not
"""
# In IXR7220_D1, the firmware running in the PSU controls the LED
# and the PSU LED state cannot be changed from CPU.
return False

View File

@ -0,0 +1,916 @@
#############################################################################
# Nokia
#
#############################################################################
import os
import sys
import time
try:
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId
from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom
from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper
from sonic_py_common import logger
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
if sys.version_info[0] < 3:
import commands as cmd
else:
import subprocess as cmd
smbus_present = 1
try:
import smbus
except ImportError as e:
smbus_present = 0
INFO_OFFSET = 128
DOM_OFFSET = 0
# definitions of the offset and width for values in XCVR info eeprom
XCVR_INTFACE_BULK_OFFSET = 0
XCVR_INTFACE_BULK_WIDTH_SFP = 21
XCVR_TYPE_OFFSET = 0
XCVR_TYPE_WIDTH = 1
XCVR_EXT_TYPE_OFFSET = 1
XCVR_EXT_TYPE_WIDTH = 1
XCVR_CONNECTOR_OFFSET = 2
XCVR_CONNECTOR_WIDTH = 1
XCVR_COMPLIANCE_CODE_OFFSET = 3
XCVR_COMPLIANCE_CODE_WIDTH = 8
XCVR_ENCODING_OFFSET = 11
XCVR_ENCODING_WIDTH = 1
XCVR_NBR_OFFSET = 12
XCVR_NBR_WIDTH = 1
XCVR_EXT_RATE_SEL_OFFSET = 13
XCVR_EXT_RATE_SEL_WIDTH = 1
XCVR_CABLE_LENGTH_OFFSET = 14
XCVR_CABLE_LENGTH_WIDTH_SFP = 6
XCVR_VENDOR_NAME_OFFSET = 20
XCVR_VENDOR_NAME_WIDTH = 16
XCVR_VENDOR_OUI_OFFSET = 37
XCVR_VENDOR_OUI_WIDTH = 3
XCVR_VENDOR_PN_OFFSET = 40
XCVR_VENDOR_PN_WIDTH = 16
XCVR_HW_REV_OFFSET = 56
XCVR_HW_REV_WIDTH_SFP = 4
XCVR_VENDOR_SN_OFFSET = 68
XCVR_VENDOR_SN_WIDTH = 16
XCVR_VENDOR_DATE_OFFSET = 84
XCVR_VENDOR_DATE_WIDTH = 8
XCVR_DOM_CAPABILITY_OFFSET = 92
XCVR_DOM_CAPABILITY_WIDTH = 2
XCVR_INTERFACE_DATA_START = 0
XCVR_INTERFACE_DATA_SIZE = 92
SFP_DOM_BULK_DATA_START = 96
SFP_DOM_BULK_DATA_SIZE = 10
SFP_MODULE_ADDRA2_OFFSET = 256
SFP_MODULE_THRESHOLD_OFFSET = 0
SFP_MODULE_THRESHOLD_WIDTH = 56
SFP_CHANNL_THRESHOLD_OFFSET = 112
SFP_CHANNL_THRESHOLD_WIDTH = 2
SFP_TEMPE_OFFSET = 96
SFP_TEMPE_WIDTH = 2
SFP_VOLT_OFFSET = 98
SFP_VOLT_WIDTH = 2
SFP_CHANNL_MON_OFFSET = 100
SFP_CHANNL_MON_WIDTH = 6
SFP_CHANNL_STATUS_OFFSET = 110
SFP_CHANNL_STATUS_WIDTH = 1
sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)',
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)')
sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode',
'ESCONComplianceCodes', 'SONETComplianceCodes',
'EthernetComplianceCodes', 'FibreChannelLinkLength',
'FibreChannelTechnology', 'SFP+CableTechnology',
'FibreChannelTransmissionMedia', 'FibreChannelSpeed')
COPPER_TYPE = "COPPER"
SFP_TYPE = "SFP"
# SFP PORT numbers
SFP_PORT_START = 49
SFP_PORT_END = 52
SYSLOG_IDENTIFIER = "xcvrd"
sonic_logger = logger.Logger(SYSLOG_IDENTIFIER)
class Sfp(SfpBase):
"""Platform-specific Sfp class"""
"""
Nokia platform-specific Sfp class
"""
# Paths
PLATFORM_ROOT_PATH = "/usr/share/sonic/device"
PMON_HWSKU_PATH = "/usr/share/sonic/hwsku"
HOST_CHK_CMD = "docker > /dev/null 2>&1"
PLATFORM = "armhf-nokia_ixs7215_52x-r0"
HWSKU = "Nokia-7215"
port_to_i2c_mapping = 0
def __init__(self, index, sfp_type, eeprom_path, port_i2c_map):
SfpBase.__init__(self)
self.index = index
self.port_num = index
self.sfp_type = sfp_type
self.eeprom_path = eeprom_path
self.port_to_i2c_mapping = port_i2c_map
self.port_name = sfp_type + str(index)
self.port_to_eeprom_mapping = {}
self.port_to_eeprom_mapping[index] = eeprom_path
self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer',
'model', 'connector', 'encoding', 'ext_identifier',
'ext_rateselect_compliance', 'cable_type', 'cable_length',
'nominal_bit_rate', 'specification_compliance',
'vendor_date', 'vendor_oui']
self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode',
'tx_disable', 'tx_disable_channel', 'temperature',
'voltage', 'rx1power', 'rx2power', 'rx3power',
'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias',
'tx1power', 'tx2power', 'tx3power', 'tx4power']
self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm',
'templowwarning', 'vcchighalarm', 'vcchighwarning',
'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm',
'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning',
'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm',
'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning',
'txbiaslowalarm', 'txbiaslowwarning']
self.dom_supported = False
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
self.calibration = 0
self._dom_capability_detect()
def __convert_string_to_num(self, value_str):
if "-inf" in value_str:
return 'N/A'
elif "Unknown" in value_str:
return 'N/A'
elif 'dBm' in value_str:
t_str = value_str.rstrip('dBm')
return float(t_str)
elif 'mA' in value_str:
t_str = value_str.rstrip('mA')
return float(t_str)
elif 'C' in value_str:
t_str = value_str.rstrip('C')
return float(t_str)
elif 'Volts' in value_str:
t_str = value_str.rstrip('Volts')
return float(t_str)
else:
return 'N/A'
def __is_host(self):
return os.system(self.HOST_CHK_CMD) == 0
def __get_path_to_port_config_file(self):
platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM])
hwsku_path = "/".join([platform_path, self.HWSKU]
) if self.__is_host() else self.PMON_HWSKU_PATH
return "/".join([hwsku_path, "port_config.ini"])
def __read_eeprom_specific_bytes(self, offset, num_bytes):
sysfsfile_eeprom = None
eeprom_raw = []
for i in range(0, num_bytes):
eeprom_raw.append("0x00")
sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num]
try:
sysfsfile_eeprom = open(
sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0)
sysfsfile_eeprom.seek(offset)
raw = sysfsfile_eeprom.read(num_bytes)
for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
except Exception as e:
pass
finally:
if sysfsfile_eeprom:
sysfsfile_eeprom.close()
return eeprom_raw
def _dom_capability_detect(self):
if self.sfp_type == "SFP":
sfpi_obj = sff8472InterfaceId()
if sfpi_obj is None:
return None
sfp_dom_capability_raw = self.__read_eeprom_specific_bytes(
XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH)
if sfp_dom_capability_raw is not None:
sfp_dom_capability = int(sfp_dom_capability_raw[0], 16)
self.dom_supported = (sfp_dom_capability & 0x40 != 0)
if self.dom_supported:
self.dom_temp_supported = True
self.dom_volt_supported = True
self.dom_rx_power_supported = True
self.dom_tx_power_supported = True
if sfp_dom_capability & 0x20 != 0:
self.calibration = 1
elif sfp_dom_capability & 0x10 != 0:
self.calibration = 2
else:
self.calibration = 0
else:
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
self.calibration = 0
self.dom_tx_disable_supported = (
int(sfp_dom_capability_raw[1], 16) & 0x40 != 0)
else:
self.dom_supported = False
self.dom_temp_supported = False
self.dom_volt_supported = False
self.dom_rx_power_supported = False
self.dom_tx_power_supported = False
def get_transceiver_info(self):
"""
Retrieves transceiver info of this SFP
Returns:
A dict which contains following keys/values :
========================================================================
keys |Value Format |Information
---------------------------|---------------|----------------------------
type |1*255VCHAR |type of SFP
hardware_rev |1*255VCHAR |hardware version of SFP
serial |1*255VCHAR |serial number of the SFP
manufacturer |1*255VCHAR |SFP vendor name
model |1*255VCHAR |SFP model name
connector |1*255VCHAR |connector information
encoding |1*255VCHAR |encoding information
ext_identifier |1*255VCHAR |extend identifier
ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance
cable_length |INT |cable length in m
nominal_bit_rate |INT |nominal bit rate by 100Mbs
specification_compliance |1*255VCHAR |specification compliance
vendor_date |1*255VCHAR |vendor date
vendor_oui |1*255VCHAR |vendor OUI
========================================================================
"""
if self.sfp_type == COPPER_TYPE:
return None
compliance_code_dict = {}
transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A')
if not self.get_presence():
return transceiver_info_dict
if self.sfp_type == SFP_TYPE:
offset = 0
vendor_rev_width = XCVR_HW_REV_WIDTH_SFP
interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP
sfpi_obj = sff8472InterfaceId()
if sfpi_obj is None:
print("Error: sfp_object open failed")
return None
sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes(
offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE)
if sfp_interface_bulk_raw is None:
return None
start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START
end = start + interface_info_bulk_width
sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_NAME_WIDTH
sfp_vendor_name_data = sfpi_obj.parse_vendor_name(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_PN_WIDTH
sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START
end = start + vendor_rev_width
sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_SN_WIDTH
sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_OUI_WIDTH
sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(
sfp_interface_bulk_raw[start: end], 0)
start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START
end = start + XCVR_VENDOR_DATE_WIDTH
sfp_vendor_date_data = sfpi_obj.parse_vendor_date(
sfp_interface_bulk_raw[start: end], 0)
transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value']
transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value']
transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value']
transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value']
transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value']
transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value']
transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[
'data']['VendorDataCode(YYYY-MM-DD Lot)']['value']
transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value']
transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value']
transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value']
transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value']
for key in sfp_cable_length_tup:
if key in sfp_interface_bulk_data['data']:
transceiver_info_dict['cable_type'] = key
transceiver_info_dict['cable_length'] = str(
sfp_interface_bulk_data['data'][key]['value'])
for key in sfp_compliance_code_tup:
if key in sfp_interface_bulk_data['data']['Specification compliance']['value']:
compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value']
transceiver_info_dict['specification_compliance'] = str(
compliance_code_dict)
transceiver_info_dict['nominal_bit_rate'] = str(
sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value'])
return transceiver_info_dict
def get_transceiver_bulk_status(self):
"""
Retrieves transceiver bulk status of this SFP
Returns:
A dict which contains following keys/values :
========================================================================
keys |Value Format |Information
---------------------------|---------------|----------------------------
rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not.
tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not.
reset_status |BOOLEAN |reset status, True if SFP in reset, False if not.
lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not.
tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not.
tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0
| |to channel 3.
temperature |INT |module temperature in Celsius
voltage |INT |supply voltage in mV
tx<n>bias |INT |TX Bias Current in mA, n is the channel number,
| |for example, tx2bias stands for tx bias of channel 2.
rx<n>power |INT |received optical power in mW, n is the channel number,
| |for example, rx2power stands for rx power of channel 2.
tx<n>power |INT |TX output power in mW, n is the channel number,
| |for example, tx2power stands for tx power of channel 2.
========================================================================
"""
transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A')
if self.sfp_type == COPPER_TYPE:
return transceiver_dom_info_dict
if self.sfp_type == SFP_TYPE:
if not self.dom_supported:
return transceiver_dom_info_dict
offset = 256
sfpd_obj = sff8472Dom()
if sfpd_obj is None:
return transceiver_dom_info_dict
sfpd_obj._calibration_type = self.calibration
dom_data_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE)
start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START
end = start + SFP_TEMPE_WIDTH
dom_temperature_data = sfpd_obj.parse_temperature(
dom_data_raw[start: end], 0)
start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START
end = start + SFP_VOLT_WIDTH
dom_voltage_data = sfpd_obj.parse_voltage(
dom_data_raw[start: end], 0)
start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START
end = start + SFP_CHANNL_MON_WIDTH
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(
dom_data_raw[start: end], 0)
transceiver_dom_info_dict['temperature'] = self.__convert_string_to_num(
dom_temperature_data['data']['Temperature']['value'])
transceiver_dom_info_dict['voltage'] = self.__convert_string_to_num(
dom_voltage_data['data']['Vcc']['value'])
transceiver_dom_info_dict['rx1power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['RXPower']['value'])
transceiver_dom_info_dict['tx1bias'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TXBias']['value'])
transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num(
dom_channel_monitor_data['data']['TXPower']['value'])
transceiver_dom_info_dict['rx_los'] = self.get_rx_los()
transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault()
transceiver_dom_info_dict['reset_status'] = self.get_reset_status()
transceiver_dom_info_dict['lp_mode'] = self.get_lpmode()
return transceiver_dom_info_dict
def get_transceiver_threshold_info(self):
"""
Retrieves transceiver threshold info of this SFP
Returns:
A dict which contains following keys/values :
========================================================================
keys |Value Format |Information
---------------------------|---------------|----------------------------
temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius.
templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius.
temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius.
templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius.
vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV.
vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV.
vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV.
vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV.
rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm.
rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm.
rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm.
rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm.
txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm.
txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm.
txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm.
txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm.
txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA.
txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA.
txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA.
txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA.
========================================================================
"""
transceiver_dom_threshold_info_dict = dict.fromkeys(
self.threshold_dict_keys, 'N/A')
if self.sfp_type == COPPER_TYPE:
return transceiver_dom_threshold_info_dict
if self.sfp_type == SFP_TYPE:
offset = SFP_MODULE_ADDRA2_OFFSET
if not self.dom_supported:
return transceiver_dom_threshold_info_dict
sfpd_obj = sff8472Dom(None, self.calibration)
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET),
SFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(
dom_module_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
# Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[
'data']['VoltageHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value']
transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value']
return transceiver_dom_threshold_info_dict
def get_reset_status(self):
"""
Retrieves the reset status of SFP
Returns:
A Boolean, True if reset enabled, False if disabled
"""
if not self.dom_supported:
return False
if self.sfp_type == COPPER_TYPE:
return False
if self.sfp_type == SFP_TYPE:
offset = 0
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH)
if dom_channel_monitor_raw is not None:
return False
else:
return True
def get_rx_los(self):
"""
Retrieves the RX LOS (lost-of-signal) status of SFP
Returns:
A Boolean, True if SFP has RX LOS, False if not.
"""
if self.sfp_type == COPPER_TYPE:
return False
if smbus_present == 0:
sonic_logger.log_info(" PMON - smbus ERROR - ")
cmdstatus, rxlosstatus = cmd.getstatusoutput('i2cget -y 0 0x41 0x4')
rxlosstatus = int(rxlosstatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x4
rxlosstatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
pos = [1, 2, 4, 8]
bit_pos = pos[self.index-SFP_PORT_START]
rxlosstatus = rxlosstatus & (bit_pos)
if rxlosstatus == 0:
return True
return False
def get_tx_fault(self):
"""
Retrieves the TX fault status of SFP
Returns:
A Boolean, True if SFP has TX fault, False if not
Note : TX fault status is lached until a call to get_tx_fault or a reset.
"""
return False
def get_tx_disable(self):
"""
Retrieves the tx_disable status of this SFP
Returns:
A Boolean, True if tx_disable is enabled, False if disabled
"""
if self.sfp_type == COPPER_TYPE:
return False
# Enable optical SFP Tx
if smbus_present == 0:
cmdstatus, disstatus = cmd.getstatusoutput('i2cget -y 0 0x41 0x5')
sonic_logger.log_info(" PMON - smbus ERROR tx- DEBUG ")
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x5
disstatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
pos = [1, 2, 4, 8]
bit_pos = pos[self.index-SFP_PORT_START]
disstatus = disstatus & (bit_pos)
if disstatus == 0:
return True
return False
def get_tx_disable_channel(self):
"""
Retrieves the TX disabled channels in this SFP
Returns:
A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent
TX channels which have been disabled in this SFP.
As an example, a returned value of 0x5 indicates that channel 0
and channel 2 have been disabled.
"""
tx_disable_list = self.get_tx_disable()
if tx_disable_list is None:
return 0
tx_disabled = 0
for i in range(len(tx_disable_list)):
if tx_disable_list[i]:
tx_disabled |= 1 << i
return tx_disabled
def get_lpmode(self):
"""
Retrieves the lpmode (low power mode) status of this SFP
Returns:
A Boolean, True if lpmode is enabled, False if disabled
"""
if self.sfp_type == COPPER_TYPE:
return False
if self.sfp_type == SFP_TYPE:
return False
def get_power_override(self):
"""
Retrieves the power-override status of this SFP
Returns:
A Boolean, True if power-override is enabled, False if disabled
"""
if self.sfp_type == COPPER_TYPE:
return False
if self.sfp_type == SFP_TYPE:
return False
def get_temperature(self):
"""
Retrieves the temperature of this SFP
Returns:
An integer number of current temperature in Celsius
"""
transceiver_bulk_status = self.get_transceiver_bulk_status()
return transceiver_bulk_status.get("temperature", "N/A")
def get_voltage(self):
"""
Retrieves the supply voltage of this SFP
Returns:
An integer number of supply voltage in mV
"""
transceiver_bulk_status = self.get_transceiver_bulk_status()
return transceiver_bulk_status.get("voltage", "N/A")
def get_tx_bias(self):
"""
Retrieves the TX bias current of this SFP
Returns:
A list of four integer numbers, representing TX bias in mA
for channel 0 to channel 4.
Ex. ['110.09', '111.12', '108.21', '112.09']
"""
transceiver_bulk_status = self.get_transceiver_bulk_status()
tx1_bs = transceiver_bulk_status.get("tx1bias", "N/A")
tx2_bs = transceiver_bulk_status.get("tx2bias", "N/A")
tx3_bs = transceiver_bulk_status.get("tx3bias", "N/A")
tx4_bs = transceiver_bulk_status.get("tx4bias", "N/A")
tx_bias_list = [tx1_bs, tx2_bs, tx3_bs, tx4_bs]
return tx_bias_list
def get_rx_power(self):
"""
Retrieves the received optical power for this SFP
Returns:
A list of four integer numbers, representing received optical
power in mW for channel 0 to channel 4.
Ex. ['1.77', '1.71', '1.68', '1.70']
"""
rx_power_list = []
if self.sfp_type == COPPER_TYPE:
return None
if self.sfp_type == SFP_TYPE:
offset = 256
sfpd_obj = sff8472Dom()
if sfpd_obj is None:
return None
if self.dom_supported:
sfpd_obj._calibration_type = self.calibration
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(
dom_channel_monitor_raw, 0)
rx_power_list.append(self.__convert_string_to_num(
dom_channel_monitor_data['data']['RXPower']['value']))
else:
return None
else:
return None
return rx_power_list
def get_tx_power(self):
"""
Retrieves the TX power of this SFP
Returns:
A list of four integer numbers, representing TX power in mW
for channel 0 to channel 4.
Ex. ['1.86', '1.86', '1.86', '1.86']
"""
tx_power_list = []
if self.sfp_type == COPPER_TYPE:
return None
if self.sfp_type == SFP_TYPE:
offset = 256
sfpd_obj = sff8472Dom()
if sfpd_obj is None:
return None
if self.dom_supported:
sfpd_obj._calibration_type = self.calibration
dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(
(offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(
dom_channel_monitor_raw, 0)
tx_power_list.append(self.__convert_string_to_num(
dom_channel_monitor_data['data']['TXPower']['value']))
else:
return None
else:
return None
return tx_power_list
def reset(self):
"""
Reset SFP and return all user module settings to their default srate.
Returns:
A boolean, True if successful, False if not
"""
if self.sfp_type == COPPER_TYPE:
return False
path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/sfp_port_reset"
port_ps = path.format(self.port_to_i2c_mapping)
try:
reg_file = open(port_ps, 'w')
except IOError as e:
# print "Error: unable to open file: %s" % str(e)
return False
# toggle reset
reg_file.seek(0)
reg_file.write('1')
time.sleep(1)
reg_file.seek(0)
reg_file.write('0')
reg_file.close()
return True
def tx_disable(self, tx_disable):
"""
Disable SFP TX for all channels
Args:
tx_disable : A Boolean, True to enable tx_disable mode, False to disable
tx_disable mode.
Returns:
A boolean, True if tx_disable is set successfully, False if not
"""
return False
def tx_disable_channel(self, channel, disable):
"""
Sets the tx_disable for specified SFP channels
Args:
channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3,
e.g. 0x5 for channel 0 and channel 2.
disable : A boolean, True to disable TX channels specified in channel,
False to enable
Returns:
A boolean, True if successful, False if not
"""
return False
def set_lpmode(self, lpmode):
"""
Sets the lpmode (low power mode) of SFP
Args:
lpmode: A Boolean, True to enable lpmode, False to disable it
Note : lpmode can be overridden by set_power_override
Returns:
A boolean, True if lpmode is set successfully, False if not
"""
if self.sfp_type == COPPER_TYPE:
return False
if self.sfp_type == SFP_TYPE:
return False
def set_power_override(self, power_override, power_set):
"""
Sets SFP power level using power_override and power_set
Args:
power_override :
A Boolean, True to override set_lpmode and use power_set
to control SFP power, False to disable SFP power control
through power_override/power_set and use set_lpmode
to control SFP power.
power_set :
Only valid when power_override is True.
A Boolean, True to set SFP to low power mode, False to set
SFP to high power mode.
Returns:
A boolean, True if power-override and power_set are set successfully,
False if not
"""
return False
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
sfputil_helper = SfpUtilHelper()
sfputil_helper.read_porttab_mappings(
self.__get_path_to_port_config_file())
name = sfputil_helper.logical[self.index] or "Unknown"
return name
def get_presence(self):
"""
Retrieves the presence
Returns:
bool: True if is present, False if not
"""
if self.sfp_type == COPPER_TYPE:
return False
if smbus_present == 0: # if called from sfputil outside of pmon
cmdstatus, sfpstatus = cmd.getstatusoutput('i2cget -y 0 0x41 0x3')
sfpstatus = int(sfpstatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x3
sfpstatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
pos = [1, 2, 4, 8]
bit_pos = pos[self.index-SFP_PORT_START]
sfpstatus = sfpstatus & (bit_pos)
if sfpstatus == 0:
return True
return False
def get_model(self):
"""
Retrieves the model number (or part number) of the device
Returns:
string: Model/part number of device
"""
transceiver_dom_info_dict = self.get_transceiver_info()
return transceiver_dom_info_dict.get("model", "N/A")
def get_serial(self):
"""
Retrieves the serial number of the device
Returns:
string: Serial number of device
"""
transceiver_dom_info_dict = self.get_transceiver_info()
return transceiver_dom_info_dict.get("serial", "N/A")
def get_status(self):
"""
Retrieves the operational status of the device
Returns:
A boolean value, True if device is operating properly, False if not
"""
return self.get_presence()

View File

@ -0,0 +1,117 @@
'''
listen for the SFP change event and return to chassis.
'''
import sys
import time
from sonic_py_common import logger
smbus_present = 1
try:
import smbus
except ImportError as e:
smbus_present = 0
if sys.version_info[0] < 3:
import commands as cmd
else:
import subprocess as cmd
# system level event/error
EVENT_ON_ALL_SFP = '-1'
SYSTEM_NOT_READY = 'system_not_ready'
SYSTEM_READY = 'system_become_ready'
SYSTEM_FAIL = 'system_fail'
# SFP PORT numbers
SFP_PORT_START = 49
SFP_PORT_END = 52
SYSLOG_IDENTIFIER = "sfp_event"
sonic_logger = logger.Logger(SYSLOG_IDENTIFIER)
class sfp_event:
''' Listen to plugin/plugout cable events '''
def __init__(self):
self.handle = None
def initialize(self):
self.modprs_register = 0
# Get Transceiver status
time.sleep(5)
self.modprs_register = self._get_transceiver_status()
sonic_logger.log_info("Initial SFP presence=%d" % self.modprs_register)
def deinitialize(self):
if self.handle is None:
return
def _get_transceiver_status(self):
if smbus_present == 0:
sonic_logger.log_info(" PMON - smbus ERROR - DEBUG sfp_event ")
cmdstatus, sfpstatus = cmd.getstatusoutput('i2cget -y 0 0x41 0x3')
sfpstatus = int(sfpstatus, 16)
else:
bus = smbus.SMBus(0)
DEVICE_ADDRESS = 0x41
DEVICE_REG = 0x3
sfpstatus = bus.read_byte_data(DEVICE_ADDRESS, DEVICE_REG)
sfpstatus = ~sfpstatus
sfpstatus = sfpstatus & 0xF
return sfpstatus
def check_sfp_status(self, port_change, timeout):
"""
check_sfp_status called from get_change_event, this will return correct
status of all 4 SFP ports if there is a change in any of them
"""
start_time = time.time()
port = SFP_PORT_START
forever = False
if timeout == 0:
forever = True
elif timeout > 0:
timeout = timeout / float(1000) # Convert to secs
else:
return False, {}
end_time = start_time + timeout
if (start_time > end_time):
return False, {} # Time wrap or possibly incorrect timeout
while (timeout >= 0):
# Check for OIR events and return updated port_change
reg_value = self._get_transceiver_status()
if (reg_value != self.modprs_register):
changed_ports = (self.modprs_register ^ reg_value)
while (port >= SFP_PORT_START and port <= SFP_PORT_END):
# Mask off the bit corresponding to our port
mask = (1 << port-SFP_PORT_START)
if (changed_ports & mask):
# ModPrsL is active high
if reg_value & mask == 0:
port_change[port] = '0'
else:
port_change[port] = '1'
port += 1
# Update reg value
self.modprs_register = reg_value
return True, port_change
if forever:
time.sleep(1)
else:
timeout = end_time - time.time()
if timeout >= 1:
time.sleep(1) # We poll at 1 second granularity
else:
if timeout > 0:
time.sleep(timeout)
return True, {}
return False, {}

View File

@ -0,0 +1 @@
This directory contains unit tests of the Platform API 2.0

View File

@ -0,0 +1,68 @@
#!/usr/bin/env python
try:
import sonic_platform.platform
import sonic_platform.chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
def main():
print("-----------------")
print("Chassis Unit Test")
print("-----------------")
chassis = sonic_platform.platform.Platform().get_chassis()
print(" Chassis name: {}".format(chassis.get_name()))
print(" Chassis presence: {}".format(chassis.get_presence()))
print(" Chassis model: {}".format(chassis.get_model()))
print(" Chassis serial: {}".format(chassis.get_serial()))
print(" Chassis status: {}".format(chassis.get_status()))
print(" Chassis serial_number: {}".format(chassis.get_serial_number()))
print(" Chassis base_mac: {}".format(chassis.get_base_mac()))
print(" Chassis reboot cause: {}\n".format(chassis.get_reboot_cause()))
print(" Chassis watchdog: {}".format(chassis.get_watchdog()))
print(" Chassis num_components: {}".format(chassis.get_num_components()))
print(" Chassis all_components: {}\n".format(chassis.get_all_components()))
print(" Chassis num_modules: {}".format(chassis.get_num_modules()))
print(" Chassis all_modules: {}\n".format(chassis.get_all_modules()))
print(" Chassis num_fans: {}".format(chassis.get_num_fans()))
print(" Chassis all_fans: {}\n".format(chassis.get_all_fans()))
print(" Chassis num_thermals: {}".format(chassis.get_num_thermals()))
print(" Chassis all_thermals: {}\n".format(chassis.get_all_thermals()))
print(" Chassis num_sfps: {}".format(chassis.get_num_sfps()))
print(" Chassis all_sfps: {}\n".format(chassis.get_all_sfps()))
print(" Chassis eeprom: {}".format(chassis.get_eeprom()))
print(" Chassis system_eeprom_info: {}\n".format(chassis.get_system_eeprom_info()))
print(" Chassis get_status_led start : {}\n".format(chassis.get_status_led()))
chassis.set_status_led('amber')
print(" Chassis get_status_led amber: {}\n".format(chassis.get_status_led()))
chassis.set_status_led('green')
print(" Chassis get_status_led green: {}\n".format(chassis.get_status_led()))
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,17 @@
#!/usr/bin/python
from sonic_platform.chassis import Chassis
def main():
print("---------------------------")
print("Chassis Component Unit Test")
print("---------------------------")
chassis = Chassis()
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,25 @@
#!/usr/bin/python
from sonic_platform.chassis import Chassis
def main():
print("------------------------")
print("Chassis eeprom Unit Test")
print("------------------------")
chassis = Chassis()
eeprom = chassis.get_eeprom()
print " Model: {}, Serial: {}".format(eeprom.modelstr(),
eeprom.serial_str())
print " Part#: {}, Serial#: {}".format(eeprom.part_number_str(),
eeprom.serial_number_str())
print " Base MAC: {}".format(eeprom.base_mac_addr())
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,27 @@
#!/usr/bin/python
from sonic_platform.chassis import Chassis
def main():
print("---------------------")
print("Chassis Fan Unit Test")
print("---------------------")
chassis = Chassis()
for fan in chassis.get_all_fans():
print(" Name:", fan.get_name())
print(" Presence: {}, Status: {}, LED: {}".format(fan.get_presence(),
fan.get_status(),
fan.get_status_led()))
print(" Model: {}, Serial: {}".format(fan.get_model(),
fan.get_serial()))
print(" Direction: {}, Speed: {}RPM, Target Speed: {}%\n".format(fan.get_direction(),
str(fan.get_speed()),
str(fan.get_target_speed())))
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,27 @@
#!/usr/bin/python
from sonic_platform.chassis import Chassis
def main():
print("---------------------")
print("Chassis PSU Unit Test")
print("---------------------")
chassis = Chassis()
for psu in chassis.get_all_psus():
print(" Name:", psu.get_name())
print(" Presence: {}, Status: {}, LED: {}".format(psu.get_presence(),
psu.get_status(),
psu.get_status_led()))
print(" Model: {}, Serial: {}".format(psu.get_model(),
psu.get_serial()))
print(" Voltage: {}, Current: {}, Power: {}\n".format(psu.get_voltage(),
psu.get_current(),
psu.get_power()))
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python
try:
import sonic_platform
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
def main():
PORT_START = 49
PORT_END = 52
chassis = sonic_platform.platform.Platform().get_chassis()
for physical_port in range(PORT_START, PORT_END+1):
print(" ")
print(" SFP transceiver tests PORT = ", physical_port)
presence = chassis.get_sfp(physical_port).get_presence()
print("TEST 1 - sfp presence [ True ] ", physical_port, presence)
status = chassis.get_sfp(physical_port).get_reset_status()
print("TEST 2 - sfp reset status [ False ] ", physical_port, status)
txdisable = chassis.get_sfp(physical_port).get_tx_disable()
print("TEST 3 - sfp tx_disable [ False ] ", physical_port, txdisable)
rxlos = chassis.get_sfp(physical_port).get_rx_los()
print("TEST 4 - sfp status rxlos [ False ] ", physical_port, rxlos)
txfault = chassis.get_sfp(physical_port).get_tx_fault()
print("TEST 5 - sfp status txfault [ False ] ", physical_port, txfault)
lpmode = chassis.get_sfp(physical_port).get_lpmode()
print("TEST 6 - sfp enable lpmode [ False ] ", physical_port, lpmode)
trans_info = chassis.get_sfp(physical_port).get_transceiver_info()
print("TEST 7 - sfp transceiver info for port:", physical_port, trans_info)
trans_status = chassis.get_sfp(physical_port).get_transceiver_bulk_status()
print("TEST 8 - sfp bulk status for port:", physical_port, trans_status)
threshold = chassis.get_sfp(physical_port).get_transceiver_threshold_info()
print("TEST 9 - sfp bulk status for port:", physical_port, threshold)
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,26 @@
#!/usr/bin/python
from sonic_platform.chassis import Chassis
def main():
print("-------------------------")
print("Chassis Thermal Unit Test")
print("-------------------------")
chassis = Chassis()
for thermal in chassis.get_all_thermals():
print(" Name:", thermal.get_name())
print(" Presence: {}, Status: {}".format(thermal.get_presence(),
thermal.get_status()))
print(" Model: {}, Serial: {}".format(thermal.get_model(),
thermal.get_serial()))
print(" Temperature: {}C, Low Threshold: {}C, High Threshold: {}C\n".format(thermal.get_temperature(),
thermal.get_low_threshold(),
thermal.get_high_threshold()))
return
if __name__ == '__main__':
main()

View File

@ -0,0 +1,226 @@
########################################################################
# Nokia IXS7215
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Thermals' information which are available in the platform
#
########################################################################
try:
import os
from sonic_platform_base.thermal_base import ThermalBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Thermal(ThermalBase):
"""Nokia platform-specific Thermal class"""
I2C_CLASS_DIR = "/sys/class/i2c-adapter/"
I2C_DEV_MAPPING = (['i2c-0/0-004a/hwmon/', 1],
['i2c-0/0-004b/hwmon/', 1],
['i2c-0/0-002e/', 1],
['i2c-0/0-002e/', 2],
['i2c-0/0-002e/', 3])
HWMON_CLASS_DIR = "/sys/class/hwmon/"
THERMAL_NAME = ("PCB PHY", "PCB MAC",
"ADT7473-CPU", "ADT7473-LOC", "ADT7473-MAC",
"CPU Core")
def __init__(self, thermal_index):
self.index = thermal_index + 1
self.is_psu_thermal = False
self.dependency = None
self.thermal_high_threshold_file = None
# PCB temperature sensors
if self.index < 3:
i2c_path = self.I2C_CLASS_DIR + self.I2C_DEV_MAPPING[self.index - 1][0]
sensor_index = self.I2C_DEV_MAPPING[self.index - 1][1]
sensor_max_suffix = "max"
sensor_crit_suffix = None
hwmon_node = os.listdir(i2c_path)[0]
self.SENSOR_DIR = i2c_path + hwmon_node + '/'
# ADT7473 temperature sensors
elif self.index < 6:
i2c_path = self.I2C_CLASS_DIR + self.I2C_DEV_MAPPING[self.index - 1][0]
sensor_index = self.I2C_DEV_MAPPING[self.index - 1][1]
sensor_max_suffix = "max"
sensor_crit_suffix = "crit"
self.SENSOR_DIR = i2c_path
# Armada 38x SOC temperature sensor
else:
dev_path = self.HWMON_CLASS_DIR
sensor_index = 1
sensor_max_suffix = None
sensor_crit_suffix = None
hwmon_node = os.listdir(dev_path)[0]
self.SENSOR_DIR = dev_path + hwmon_node + '/'
# sysfs file for current temperature value
self.thermal_temperature_file = self.SENSOR_DIR \
+ "temp{}_input".format(sensor_index)
# sysfs file for high threshold value if supported for this sensor
if sensor_max_suffix:
self.thermal_high_threshold_file = self.SENSOR_DIR \
+ "temp{}_{}".format(sensor_index, sensor_max_suffix)
else:
self.thermal_high_threshold_file = None
# sysfs file for crit high threshold value if supported for this sensor
if sensor_crit_suffix:
self.thermal_high_crit_threshold_file = self.SENSOR_DIR \
+ "temp{}_{}".format(sensor_index, sensor_crit_suffix)
else:
self.thermal_high_crit_threshold_file = None
def _read_sysfs_file(self, sysfs_file):
# On successful read, returns the value read from given
# sysfs_file and on failure returns 'ERR'
rv = 'ERR'
if (not os.path.isfile(sysfs_file)):
return rv
try:
with open(sysfs_file, 'r') as fd:
rv = fd.read()
except Exception as e:
rv = 'ERR'
rv = rv.rstrip('\r\n')
rv = rv.lstrip(" ")
return rv
def get_name(self):
"""
Retrieves the name of the thermal
Returns:
string: The name of the thermal
"""
return self.THERMAL_NAME[self.index - 1]
def get_presence(self):
"""
Retrieves the presence of the thermal
Returns:
bool: True if thermal is present, False if not
"""
if self.dependency:
return self.dependency.get_presence()
else:
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the Thermal
Returns:
string: Model/part number of Thermal
"""
return 'NA'
def get_serial(self):
"""
Retrieves the serial number of the Thermal
Returns:
string: Serial number of Thermal
"""
return 'NA'
def get_status(self):
"""
Retrieves the operational status of the thermal
Returns:
A boolean value, True if thermal is operating properly,
False if not
"""
if self.dependency:
return self.dependency.get_status()
else:
return True
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to
nearest thousandth of one degree Celsius, e.g. 30.125
"""
thermal_temperature = self._read_sysfs_file(
self.thermal_temperature_file)
if (thermal_temperature != 'ERR'):
thermal_temperature = float(thermal_temperature) / 1000
else:
thermal_temperature = 0
return float("{:.3f}".format(thermal_temperature))
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
# Not implemented for this sensor
if not self.thermal_high_threshold_file:
raise NotImplementedError
thermal_high_threshold = self._read_sysfs_file(
self.thermal_high_threshold_file)
if (thermal_high_threshold != 'ERR'):
thermal_high_threshold = float(thermal_high_threshold) / 1000
else:
thermal_high_threshold = 0.0
return float("{:.3f}".format(thermal_high_threshold))
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one
degree Celsius, e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if
not
"""
# Thermal threshold values are pre-defined based on HW.
return False
def get_high_critical_threshold(self):
"""
Retrieves the high critical threshold temperature of thermal
Returns:
A float number, the high critical threshold temperature of thermal in Celsius
up to nearest thousandth of one degree Celsius, e.g. 30.125
"""
# Not implemented for this sensor
if not self.thermal_high_crit_threshold_file:
raise NotImplementedError
thermal_high_crit_threshold = self._read_sysfs_file(
self.thermal_high_crit_threshold_file)
if (thermal_high_crit_threshold != 'ERR'):
thermal_high_crit_threshold = float(thermal_high_crit_threshold) / 1000
else:
thermal_high_crit_threshold = 0.0
return float("{:.3f}".format(thermal_high_crit_threshold))

View File

@ -0,0 +1,192 @@
from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
from sonic_py_common import logger
sonic_logger = logger.Logger('thermal_actions')
class SetFanSpeedAction(ThermalPolicyActionBase):
"""
Base thermal action class to set speed for fans
"""
# JSON field definition
JSON_FIELD_SPEED = 'speed'
JSON_FIELD_DEFAULT_SPEED = 'default_speed'
JSON_FIELD_HIGHTEMP_SPEED = 'hightemp_speed'
def __init__(self):
"""
Constructor of SetFanSpeedAction
"""
self.default_speed = 50
self.hightemp_speed = 100
self.speed = self.default_speed
def load_from_json(self, json_obj):
"""
Construct SetFanSpeedAction via JSON. JSON example:
{
"type": "fan.all.set_speed"
"speed": "100"
}
:param json_obj: A JSON object representing a SetFanSpeedAction action.
:return:
"""
if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj:
speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED])
if speed < 0 or speed > 100:
raise ValueError('SetFanSpeedAction invalid speed value {} in JSON policy file, valid value should be [0, 100]'.
format(speed))
self.speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED])
else:
raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'.
format(SetFanSpeedAction.JSON_FIELD_SPEED))
@classmethod
def set_all_fan_speed(cls, thermal_info_dict, speed):
from .thermal_infos import FanInfo
if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo):
fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME]
for fan in fan_info_obj.get_presence_fans():
fan.set_speed(int(speed))
@thermal_json_object('fan.all.set_speed')
class SetAllFanSpeedAction(SetFanSpeedAction):
"""
Action to set speed for all fans
"""
def execute(self, thermal_info_dict):
"""
Set speed for all fans
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
SetAllFanSpeedAction.set_all_fan_speed(thermal_info_dict, self.speed)
@thermal_json_object('thermal.temp_check_and_set_all_fan_speed')
class ThermalRecoverAction(SetFanSpeedAction):
"""
Action to check thermal sensor temperature change status and set speed for all fans
"""
def load_from_json(self, json_obj):
"""
Construct ThermalRecoverAction via JSON. JSON example:
{
"type": "thermal.temp_check_and_set_all_fan_speed"
"default_speed": "50"
"hightemp_speed": "100"
}
:param json_obj: A JSON object representing a ThermalRecoverAction action.
:return:
"""
if SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED in json_obj:
default_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED])
if default_speed < 0 or default_speed > 100:
raise ValueError('SetFanSpeedAction invalid default speed value {} in JSON policy file, valid value should be [0, 100]'.
format(default_speed))
self.default_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED])
else:
raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'.
format(SetFanSpeedAction.JSON_FIELD_DEFAULT_SPEED))
if SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED in json_obj:
hightemp_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED])
if hightemp_speed < 0 or hightemp_speed > 100:
raise ValueError('SetFanSpeedAction invalid hightemp speed value {} in JSON policy file, valid value should be [0, 100]'.
format(hightemp_speed))
self.hightemp_speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED])
else:
raise ValueError('SetFanSpeedAction missing mandatory field {} in JSON policy file'.
format(SetFanSpeedAction.JSON_FIELD_HIGHTEMP_SPEED))
sonic_logger.log_warning("ThermalRecoverAction: default: {}, hightemp: {}".format(self.default_speed, self.hightemp_speed))
def execute(self, thermal_info_dict):
"""
Check check thermal sensor temperature change status and set speed for all fans
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
from .thermal_infos import ThermalInfo
if ThermalInfo.INFO_NAME in thermal_info_dict and \
isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo):
thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME]
if thermal_info_obj.is_warm_up_and_over_high_threshold():
ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.hightemp_speed)
elif thermal_info_obj.is_cool_down_and_below_low_threshold():
ThermalRecoverAction.set_all_fan_speed(thermal_info_dict, self.default_speed)
@thermal_json_object('switch.shutdown')
class SwitchPolicyAction(ThermalPolicyActionBase):
"""
Base class for thermal action. Once all thermal conditions in a thermal policy are matched,
all predefined thermal action will be executed.
"""
def execute(self, thermal_info_dict):
"""
Take action when thermal condition matches. For example, adjust speed of fan or shut
down the switch.
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
sonic_logger.log_warning("Alarm for temperature critical is detected, reboot Device")
# import os
# os.system('reboot')
@thermal_json_object('thermal_control.control')
class ControlThermalAlgoAction(ThermalPolicyActionBase):
"""
Action to control the thermal control algorithm
"""
# JSON field definition
JSON_FIELD_STATUS = 'status'
def __init__(self):
self.status = True
def load_from_json(self, json_obj):
"""
Construct ControlThermalAlgoAction via JSON. JSON example:
{
"type": "thermal_control.control"
"status": "true"
}
:param json_obj: A JSON object representing a ControlThermalAlgoAction action.
:return:
"""
if ControlThermalAlgoAction.JSON_FIELD_STATUS in json_obj:
status_str = json_obj[ControlThermalAlgoAction.JSON_FIELD_STATUS].lower()
if status_str == 'true':
self.status = True
elif status_str == 'false':
self.status = False
else:
raise ValueError('Invalid {} field value, please specify true of false'.
format(ControlThermalAlgoAction.JSON_FIELD_STATUS))
else:
raise ValueError('ControlThermalAlgoAction '
'missing mandatory field {} in JSON policy file'.
format(ControlThermalAlgoAction.JSON_FIELD_STATUS))
def execute(self, thermal_info_dict):
"""
Disable thermal control algorithm
:param thermal_info_dict: A dictionary stores all thermal information.
:return:
"""
from .thermal_infos import ChassisInfo
if ChassisInfo.INFO_NAME in thermal_info_dict:
chassis_info_obj = thermal_info_dict[ChassisInfo.INFO_NAME]
chassis = chassis_info_obj.get_chassis()
thermal_manager = chassis.get_thermal_manager()
if self.status:
thermal_manager.start_thermal_control_algorithm()
else:
thermal_manager.stop_thermal_control_algorithm()

View File

@ -0,0 +1,81 @@
from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
class FanCondition(ThermalPolicyConditionBase):
def get_fan_info(self, thermal_info_dict):
from .thermal_infos import FanInfo
if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo):
return thermal_info_dict[FanInfo.INFO_NAME]
else:
return None
@thermal_json_object('fan.any.absence')
class AnyFanAbsenceCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False
@thermal_json_object('fan.all.absence')
class AllFanAbsenceCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_presence_fans()) == 0 if fan_info_obj else False
@thermal_json_object('fan.all.presence')
class AllFanPresenceCondition(FanCondition):
def is_match(self, thermal_info_dict):
fan_info_obj = self.get_fan_info(thermal_info_dict)
return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False
class ThermalCondition(ThermalPolicyConditionBase):
def get_thermal_info(self, thermal_info_dict):
from .thermal_infos import ThermalInfo
if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo):
return thermal_info_dict[ThermalInfo.INFO_NAME]
else:
return None
@thermal_json_object('thermal.over.high_critical_threshold')
class ThermalOverHighCriticalCondition(ThermalCondition):
def is_match(self, thermal_info_dict):
thermal_info_obj = self.get_thermal_info(thermal_info_dict)
if thermal_info_obj:
return thermal_info_obj.is_over_high_critical_threshold()
else:
return False
class PsuCondition(ThermalPolicyConditionBase):
def get_psu_info(self, thermal_info_dict):
from .thermal_infos import PsuInfo
if PsuInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[PsuInfo.INFO_NAME], PsuInfo):
return thermal_info_dict[PsuInfo.INFO_NAME]
else:
return None
@thermal_json_object('psu.any.absence')
class AnyPsuAbsenceCondition(PsuCondition):
def is_match(self, thermal_info_dict):
psu_info_obj = self.get_psu_info(thermal_info_dict)
return len(psu_info_obj.get_absence_psus()) > 0 if psu_info_obj else False
@thermal_json_object('psu.all.absence')
class AllPsuAbsenceCondition(PsuCondition):
def is_match(self, thermal_info_dict):
psu_info_obj = self.get_psu_info(thermal_info_dict)
return len(psu_info_obj.get_presence_psus()) == 0 if psu_info_obj else False
@thermal_json_object('psu.all.presence')
class AllPsuPresenceCondition(PsuCondition):
def is_match(self, thermal_info_dict):
psu_info_obj = self.get_psu_info(thermal_info_dict)
return len(psu_info_obj.get_absence_psus()) == 0 if psu_info_obj else False

View File

@ -0,0 +1,210 @@
from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase
from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object
@thermal_json_object('fan_info')
class FanInfo(ThermalPolicyInfoBase):
"""
Fan information needed by thermal policy
"""
# Fan information name
INFO_NAME = 'fan_info'
def __init__(self):
self._absence_fans = set()
self._presence_fans = set()
self._status_changed = False
def collect(self, chassis):
"""
Collect absence and presence fans.
:param chassis: The chassis object
:return:
"""
self._status_changed = False
for fan in chassis.get_all_fans():
if fan.get_presence() and fan not in self._presence_fans:
self._presence_fans.add(fan)
self._status_changed = True
if fan in self._absence_fans:
self._absence_fans.remove(fan)
elif not fan.get_presence() and fan not in self._absence_fans:
self._absence_fans.add(fan)
self._status_changed = True
if fan in self._presence_fans:
self._presence_fans.remove(fan)
def get_absence_fans(self):
"""
Retrieves absence fans
:return: A set of absence fans
"""
return self._absence_fans
def get_presence_fans(self):
"""
Retrieves presence fans
:return: A set of presence fans
"""
return self._presence_fans
def is_status_changed(self):
"""
Retrieves if the status of fan information changed
:return: True if status changed else False
"""
return self._status_changed
@thermal_json_object('thermal_info')
class ThermalInfo(ThermalPolicyInfoBase):
"""
Thermal information needed by thermal policy
"""
# Fan information name
INFO_NAME = 'thermal_info'
def __init__(self):
self.init = False
self._old_avg_temp = 0
self._current_avg_temp = 0
self._high_crital_threshold = 75
self._high_threshold = 45
self._low_threshold = 40
def collect(self, chassis):
"""
Collect thermal sensor temperature change status
:param chassis: The chassis object
:return:
"""
self._temps = []
self._over_high_critical_threshold = False
self._warm_up_and_over_high_threshold = False
self._cool_down_and_below_low_threshold = False
# Calculate average temp within the device
temp = 0
num_of_thermals = chassis.get_num_thermals()
for index in range(num_of_thermals):
self._temps.insert(index, chassis.get_thermal(index).get_temperature())
temp += self._temps[index]
self._current_avg_temp = temp / num_of_thermals
# Special case if first time
if self.init is False:
self._old_avg_temp = self._current_avg_temp
self.init = True
# Check if new average temp exceeds high threshold value
if self._current_avg_temp >= self._old_avg_temp and self._current_avg_temp >= self._high_threshold:
self._warm_up_and_over_high_threshold = True
# Check if new average temp exceeds low threshold value
if self._current_avg_temp <= self._old_avg_temp and self._current_avg_temp <= self._low_threshold:
self._cool_down_and_below_low_threshold = True
self._old_avg_temp = self._current_avg_temp
def is_warm_up_and_over_high_threshold(self):
"""
Retrieves if the temperature is warm up and over high threshold
:return: True if the temperature is warm up and over high threshold else False
"""
return self._warm_up_and_over_high_threshold
def is_cool_down_and_below_low_threshold(self):
"""
Retrieves if the temperature is cold down and below low threshold
:return: True if the temperature is cold down and below low threshold else False
"""
return self._cool_down_and_below_low_threshold
def is_over_high_critical_threshold(self):
"""
Retrieves if the temperature is over high critical threshold
:return: True if the temperature is over high critical threshold else False
"""
return self._over_high_critical_threshold
@thermal_json_object('psu_info')
class PsuInfo(ThermalPolicyInfoBase):
"""
PSU information needed by thermal policy
"""
INFO_NAME = 'psu_info'
def __init__(self):
self._absence_psus = set()
self._presence_psus = set()
self._status_changed = False
def collect(self, chassis):
"""
Collect absence and presence PSUs.
:param chassis: The chassis object
:return:
"""
self._status_changed = False
for psu in chassis.get_all_psus():
if psu.get_presence() and psu.get_powergood_status() and psu not in self._presence_psus:
self._presence_psus.add(psu)
self._status_changed = True
if psu in self._absence_psus:
self._absence_psus.remove(psu)
elif (not psu.get_presence() or not psu.get_powergood_status()) and psu not in self._absence_psus:
self._absence_psus.add(psu)
self._status_changed = True
if psu in self._presence_psus:
self._presence_psus.remove(psu)
def get_absence_psus(self):
"""
Retrieves presence PSUs
:return: A set of absence PSUs
"""
return self._absence_psus
def get_presence_psus(self):
"""
Retrieves presence PSUs
:return: A set of presence fans
"""
return self._presence_psus
def is_status_changed(self):
"""
Retrieves if the status of PSU information changed
:return: True if status changed else False
"""
return self._status_changed
@thermal_json_object('chassis_info')
class ChassisInfo(ThermalPolicyInfoBase):
"""
Chassis information needed by thermal policy
"""
INFO_NAME = 'chassis_info'
def __init__(self):
self._chassis = None
def collect(self, chassis):
"""
Collect platform chassis.
:param chassis: The chassis object
:return:
"""
self._chassis = chassis
def get_chassis(self):
"""
Retrieves platform chassis object
:return: A platform chassis object.
"""
return self._chassis

View File

@ -0,0 +1,49 @@
from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase
from .thermal_actions import *
from .thermal_conditions import *
from .thermal_infos import *
class ThermalManager(ThermalManagerBase):
THERMAL_ALGORITHM_CONTROL_PATH = '/var/run/hw-management/config/suspend'
@classmethod
def start_thermal_control_algorithm(cls):
"""
Start thermal control algorithm
Returns:
bool: True if set success, False if fail.
"""
cls._control_thermal_control_algorithm(False)
@classmethod
def stop_thermal_control_algorithm(cls):
"""
Stop thermal control algorithm
Returns:
bool: True if set success, False if fail.
"""
cls._control_thermal_control_algorithm(True)
@classmethod
def _control_thermal_control_algorithm(cls, suspend):
"""
Control thermal control algorithm
Args:
suspend: Bool, indicate suspend the algorithm or not
Returns:
bool: True if set success, False if fail.
"""
status = True
write_value = 1 if suspend else 0
try:
with open(cls.THERMAL_ALGORITHM_CONTROL_PATH, 'w') as control_file:
control_file.write(str(write_value))
except (ValueError, IOError):
status = False
return status

View File

@ -0,0 +1,135 @@
"""
ARMADA 38x Watchdog - one 32 bit cpu watchdog per cpu - 2 watchdogs ( page 662)
Module contains an implementation of SONiC Platform Base API and
provides access to hardware watchdog
"""
import os
import fcntl
import array
from sonic_platform_base.watchdog_base import WatchdogBase
from sonic_py_common import logger
""" ioctl constants """
IO_READ = 0x80000000
IO_SIZE_INT = 0x00040000
IO_TYPE_WATCHDOG = ord('W') << 8
WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG
""" Watchdog ioctl commands """
WDIOC_SETOPTIONS = 4 | WDR_INT
WDIOC_KEEPALIVE = 5 | WDR_INT
WDIOC_GETTIMEOUT = 7 | WDR_INT
""" Watchdog status constants """
WDIOS_DISABLECARD = 0x0001
WDIOS_ENABLECARD = 0x0002
""" watchdog sysfs """
WD_SYSFS_PATH = "/sys/class/watchdog/"
WD_COMMON_ERROR = -1
sonic_logger = logger.Logger()
class WatchdogImplBase(WatchdogBase):
"""
Base class that implements common logic for interacting
with watchdog using ioctl commands
"""
def __init__(self, wd_device_path):
"""
Open a watchdog handle
@param wd_device_path Path to watchdog device
"""
self.watchdog_path = wd_device_path
self.watchdog = os.open(self.watchdog_path, os.O_WRONLY)
# Opening a watchdog descriptor starts
# watchdog timer; by default it should be stopped
self._disablewatchdog()
self.armed = False
self.timeout = self._gettimeout()
def disarm(self):
"""
Disarm the hardware watchdog
Returns:
A boolean, True if watchdog is disarmed successfully, False
if not
"""
sonic_logger.log_info(" Debug disarm watchdog ")
try:
self._disablewatchdog()
self.armed = False
self.timeout = 0
except IOError:
return False
return True
def _disablewatchdog(self):
"""
Turn off the watchdog timer
"""
req = array.array('h', [WDIOS_DISABLECARD])
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
def _gettimeout(self):
"""
Get watchdog timeout
@return watchdog timeout
"""
req = array.array('I', [0])
fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True)
return int(req[0])
def arm(self, seconds):
"""
Implements arm WatchdogBase API
"""
sonic_logger.log_info(" Debug arm watchdog4 ")
ret = WD_COMMON_ERROR
if seconds < 0:
return ret
try:
if self.timeout != seconds:
self.timeout = self._settimeout(seconds)
if self.armed:
self._keepalive()
else:
sonic_logger.log_info(" Debug arm watchdog5 ")
self._enablewatchdog()
self.armed = True
ret = self.timeout
except IOError:
pass
return ret
def _enablewatchdog(self):
"""
Turn on the watchdog timer
"""
req = array.array('h', [WDIOS_ENABLECARD])
fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False)
def _keepalive(self):
"""
Keep alive watchdog timer
"""
fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE)

View File

@ -0,0 +1,5 @@
sonic-platform-nokia-7215 (1.0) unstable; urgency=low
* Add support for nokia-7215.
-- Nokia <carl.keene@nokia.com> Wed, 15 Apr 2020 09:35:58 +0800

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,15 @@
Source: sonic-platform-nokia-7215
Section: unknown
Priority: optional
Maintainer: Nokia <carl.keene@nokia.com>
Build-Depends: debhelper (>=9)
Standards-Version: 3.9.6
Homepage: <insert the upstream URL, if relevant>
#Vcs-Git: git://anonscm.debian.org/collab-maint/sonic-platform-et6448m.git
#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/sonic-platform-et6448m.git
Package: sonic-platform-nokia-7215
Architecture: armhf
Depends: ${misc:Depends}
Description: <insert up to 60 chars description>
<insert long description, indented with spaces>

View File

@ -0,0 +1,66 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#export DH_VERBOSE = 1
include /usr/share/dpkg/pkg-info.mk
#--------------------------------------------------------
PACKAGE_PRE_NAME := sonic-platform-nokia
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= 7215
UTILS_DIR := utils
SERVICE_DIR := service
PLATFORM_DIR := sonic_platform
%:
dh $@ --with systemd,python2,python3 --buildsystem=pybuild
clean:
dh_testdir
dh_testroot
dh_clean
build:
(for mod in $(MODULE_DIRS); do \
python2 $${mod}/setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \
python3 $${mod}/setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \
done)
binary: binary-arch binary-indep
# Nothing to do
binary-arch:
# Nothing to do
binary-indep:
dh_testdir
dh_installdirs
# Custom package commands
(for mod in $(MODULE_DIRS); do \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/local/bin; \
cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \
cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \
python2 $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \
python3 $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \
done)
# Resuming debhelper scripts
dh_testroot
dh_install
dh_installchangelogs
dh_installdocs
dh_systemd_enable
dh_installinit
dh_systemd_start
dh_link
dh_fixperms
dh_compress
dh_strip
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
.PHONY: build binary binary-arch binary-indep clean

View File

@ -0,0 +1,5 @@
nokia-7215_plt_setup.sh usr/sbin
7215/scripts/nokia-7215init.sh usr/local/bin
7215/service/nokia-7215init.service etc/systemd/system
7215/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/armhf-nokia_ixs7215_52x-r0
7215/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/armhf-nokia_ixs7215_52x-r0

View File

@ -0,0 +1,11 @@
#!/bin/sh
# postinst script for sonic-platform-nokia-7215
#
# see: dh_installdeb(1)
sh /usr/sbin/nokia-7215_plt_setup.sh
systemctl enable nokia-7215init.service
systemctl start nokia-7215init.service
exit 0

View File

@ -0,0 +1,35 @@
#!/bin/bash
fw_uboot_env_cfg()
{
echo "Setting up U-Boot environment..."
MACH_FILE="/host/machine.conf"
PLATFORM=`sed -n 's/onie_platform=\(.*\)/\1/p' $MACH_FILE`
if [ "$PLATFORM" = "armhf-nokia_ixs7215_52x-r0" ]; then
# Ixs7215 / IPD6448M board Uboot ENV offset
FW_ENV_DEFAULT='/dev/mtd0 0x00100000 0x10000 0x10000'
demo_part=$(sgdisk -p /dev/sda | grep -e "SONiC-OS")
if [ -z "$demo_part" ]; then
# ET6448M Board - For Backward compatibility
FW_ENV_DEFAULT='/dev/mtd0 0x00500000 0x80000 0x100000 8'
fi
else
FW_ENV_DEFAULT='/dev/mtd0 0x00500000 0x80000 0x100000 8'
fi
echo "Using pre-configured uboot env"
echo $FW_ENV_DEFAULT > /etc/fw_env.config
}
main()
{
fw_uboot_env_cfg
echo "Nokia-IXS7215: /dev/mtd0 FW_ENV_DEFAULT"
}
main $@