[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:
parent
3be3f4d104
commit
0a9d7a2145
@ -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 %}
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,2 @@
|
|||||||
|
switchMacAddress=XX:XX:XX:XX:XX:XX
|
||||||
|
ledMode=ac3x97bits
|
@ -0,0 +1,3 @@
|
|||||||
|
switchMacAddress=XX:XX:XX:XX:XX:XX
|
||||||
|
inbandMgmtPortNum=48
|
||||||
|
ledMode=ac3x97bits
|
@ -0,0 +1,2 @@
|
|||||||
|
switchMacAddress=XX:XX:XX:XX:XX:XX
|
||||||
|
ledMode=ac3x97bits
|
@ -0,0 +1,3 @@
|
|||||||
|
mode=1
|
||||||
|
hwId=et6448m
|
||||||
|
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/profile.ini
|
1
device/nokia/armhf-nokia_ixs7215_52x-r0/default_sku
Normal file
1
device/nokia/armhf-nokia_ixs7215_52x-r0/default_sku
Normal file
@ -0,0 +1 @@
|
|||||||
|
Nokia-7215 l2
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"chassis": {
|
||||||
|
"7215 IXS-T1": {
|
||||||
|
"component": {
|
||||||
|
"U-Boot": { },
|
||||||
|
"System-CPLD": { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/eeprom.py
Normal file
14
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/eeprom.py
Normal 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)
|
125
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/led_control.py
Normal file
125
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/led_control.py
Normal 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
|
32
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/psuutil.py
Executable file
32
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/psuutil.py
Executable 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
|
65
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/sfputil.py
Executable file
65
device/nokia/armhf-nokia_ixs7215_52x-r0/plugins/sfputil.py
Executable 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
|
19
device/nokia/armhf-nokia_ixs7215_52x-r0/sensors.conf
Normal file
19
device/nokia/armhf-nokia_ixs7215_52x-r0/sensors.conf
Normal 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
|
65
device/nokia/armhf-nokia_ixs7215_52x-r0/thermal_policy.json
Normal file
65
device/nokia/armhf-nokia_ixs7215_52x-r0/thermal_policy.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -5,7 +5,8 @@ $(SONIC_ONE_IMAGE)_MACHINE = marvell-armhf
|
|||||||
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
|
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
|
||||||
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
|
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
|
||||||
$(SONIC_ONE_IMAGE)_INSTALLS += $(LINUX_KERNEL_DTB)
|
$(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)
|
ifeq ($(INSTALL_DEBUG_TOOLS),y)
|
||||||
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES)
|
$(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))
|
$(SONIC_ONE_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES))
|
||||||
|
11
platform/marvell-armhf/platform-nokia.mk
Normal file
11
platform/marvell-armhf/platform-nokia.mk
Normal 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)
|
@ -100,7 +100,11 @@ prepare_boot_menu() {
|
|||||||
fw_setenv ${FW_ARG} sonic_version_2 $sonic_version_2 > /dev/null
|
fw_setenv ${FW_ARG} sonic_version_2 $sonic_version_2 > /dev/null
|
||||||
BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";echo;'
|
BOOT1='echo " > Boot1: $sonic_version_1 - run sonic_image_1";echo;'
|
||||||
BOOT2='echo " > Boot2: $sonic_version_2 - run sonic_image_2";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;'
|
BOOT3='echo " > Boot3: ONIE - run onie_nand_boot";echo;'
|
||||||
|
fi
|
||||||
BORDER='echo "---------------------------------------------------";echo;'
|
BORDER='echo "---------------------------------------------------";echo;'
|
||||||
fw_setenv ${FW_ARG} print_menu $BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER > /dev/null
|
fw_setenv ${FW_ARG} print_menu $BORDER $BOOT1 $BOOT2 $BOOT3 $BORDER > /dev/null
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ include $(PLATFORM_PATH)/docker-ptf-mrvl.mk
|
|||||||
include $(PLATFORM_PATH)/one-image.mk
|
include $(PLATFORM_PATH)/one-image.mk
|
||||||
include $(PLATFORM_PATH)/linux-kernel-armhf.mk
|
include $(PLATFORM_PATH)/linux-kernel-armhf.mk
|
||||||
include $(PLATFORM_PATH)/platform-et6448m.mk
|
include $(PLATFORM_PATH)/platform-et6448m.mk
|
||||||
|
include $(PLATFORM_PATH)/platform-nokia.mk
|
||||||
|
|
||||||
INCLUDE_SYSTEM_TELEMETRY = ""
|
INCLUDE_SYSTEM_TELEMETRY = ""
|
||||||
ENABLE_SYNCD_RPC = ""
|
ENABLE_SYNCD_RPC = ""
|
||||||
|
61
platform/marvell-armhf/sonic-platform-nokia/7215/scripts/nokia-7215init.sh
Executable file
61
platform/marvell-armhf/sonic-platform-nokia/7215/scripts/nokia-7215init.sh
Executable 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
|
@ -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
|
15
platform/marvell-armhf/sonic-platform-nokia/7215/setup.py
Executable file
15
platform/marvell-armhf/sonic-platform-nokia/7215/setup.py
Executable 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'},
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
|
377
platform/marvell-armhf/sonic-platform-nokia/7215/sonic_platform/chassis.py
Executable file
377
platform/marvell-armhf/sonic-platform-nokia/7215/sonic_platform/chassis.py
Executable 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
|
@ -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
|
@ -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
|
@ -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
|
@ -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'
|
22
platform/marvell-armhf/sonic-platform-nokia/7215/sonic_platform/platform.py
Executable file
22
platform/marvell-armhf/sonic-platform-nokia/7215/sonic_platform/platform.py
Executable 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()
|
@ -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
|
@ -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()
|
@ -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, {}
|
@ -0,0 +1 @@
|
|||||||
|
This directory contains unit tests of the Platform API 2.0
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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()
|
@ -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))
|
@ -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()
|
@ -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
|
@ -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
|
@ -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
|
@ -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)
|
5
platform/marvell-armhf/sonic-platform-nokia/debian/changelog
Executable file
5
platform/marvell-armhf/sonic-platform-nokia/debian/changelog
Executable 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
|
@ -0,0 +1 @@
|
|||||||
|
9
|
15
platform/marvell-armhf/sonic-platform-nokia/debian/control
Executable file
15
platform/marvell-armhf/sonic-platform-nokia/debian/control
Executable 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>
|
66
platform/marvell-armhf/sonic-platform-nokia/debian/rules
Executable file
66
platform/marvell-armhf/sonic-platform-nokia/debian/rules
Executable 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
|
@ -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
|
@ -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
|
||||||
|
|
35
platform/marvell-armhf/sonic-platform-nokia/nokia-7215_plt_setup.sh
Executable file
35
platform/marvell-armhf/sonic-platform-nokia/nokia-7215_plt_setup.sh
Executable 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 $@
|
Loading…
Reference in New Issue
Block a user