Skip to content

Commit 5e3b66a

Browse files
qnosmssonicbld
authored andcommitted
[Seastone] DX010 platform switch to sfp-refactor based sfp impl (sonic-net#13972)
Why I did it sonic-sfp based sfp impl would be deprecated in future, change to sfp-refactor based implementation. How I did it Use the new sfp-refactor based sfp implementation for seastone. How to verify it Manual test sfp platform api or run sfp platform test cases.
1 parent 1cf4c84 commit 5e3b66a

2 files changed

Lines changed: 272 additions & 2 deletions

File tree

device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ def __initialize_sfp(self):
5151
port_config_file_path = device_info.get_path_to_port_config_file()
5252
sfputil_helper.read_porttab_mappings(port_config_file_path, 0)
5353

54-
from sonic_platform.sfp import Sfp
54+
from sonic_platform.sfp_optoe import SfpOptoe
5555
for index in range(0, NUM_SFP):
56-
sfp = Sfp(index, sfputil_helper.logical[index])
56+
sfp = SfpOptoe(index, sfputil_helper.physical_to_logical[index + 1])
5757
self._sfp_list.append(sfp)
5858
self.sfp_module_initialized = True
5959

Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
#!/usr/bin/env python
2+
3+
#############################################################################
4+
# Celestica
5+
#
6+
# Module contains an implementation of SONiC Platform Base API and
7+
# provides the sfp status which are available in the platform
8+
#
9+
#############################################################################
10+
11+
import time
12+
13+
try:
14+
from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase
15+
from .helper import APIHelper
16+
except ImportError as e:
17+
raise ImportError(str(e) + "- required module not found")
18+
19+
20+
SFP_I2C_START = 26
21+
I2C_EEPROM_PATH = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom'
22+
23+
24+
class SfpOptoe(SfpOptoeBase):
25+
"""Platform-specific SfpOptoe class"""
26+
27+
RESET_PATH = "/sys/devices/platform/dx010_cpld/qsfp_reset"
28+
LP_PATH = "/sys/devices/platform/dx010_cpld/qsfp_lpmode"
29+
PRS_PATH = "/sys/devices/platform/dx010_cpld/qsfp_modprs"
30+
31+
def __init__(self, sfp_index=0, sfp_name=None):
32+
SfpOptoeBase.__init__(self)
33+
34+
self._index = sfp_index
35+
self._port_num = self._index + 1
36+
self._api_helper = APIHelper()
37+
self._name = sfp_name
38+
self._sfp_type = None
39+
40+
def _detect_sfp_type(self):
41+
sfp_type = 'N/A'
42+
info = self.get_transceiver_info()
43+
if info:
44+
sfp_type = info.get("type_abbrv_name")
45+
# XXX: Need this hack until xcvrd is refactored
46+
if sfp_type in ["OSFP-8X", "QSFP-DD"]:
47+
sfp_type = "QSFP_DD"
48+
return sfp_type
49+
50+
@property
51+
def sfp_type(self):
52+
if self._sfp_type is None:
53+
self._sfp_type = self._detect_sfp_type()
54+
return self._sfp_type
55+
56+
def get_eeprom_path(self):
57+
port_to_i2c_mapping = SFP_I2C_START + self._index
58+
port_eeprom_path = I2C_EEPROM_PATH.format(port_to_i2c_mapping)
59+
return port_eeprom_path
60+
61+
def get_name(self):
62+
"""
63+
Retrieves the name of the device
64+
Returns:
65+
string: The name of the device
66+
"""
67+
return self._name
68+
69+
def get_status(self):
70+
"""
71+
Retrieves the operational status of the device
72+
Returns:
73+
A boolean value, True if device is operating properly, False if not
74+
"""
75+
if not self.get_presence():
76+
return False
77+
reset = self.get_reset_status()
78+
if reset:
79+
status = False
80+
else:
81+
status = True
82+
return status
83+
84+
def get_reset_status(self):
85+
"""
86+
Retrieves the reset status of SFP
87+
Returns:
88+
A Boolean, True if reset enabled, False if disabled
89+
"""
90+
reset_status_raw = self._api_helper.read_txt_file(
91+
self.RESET_PATH).rstrip()
92+
if not reset_status_raw:
93+
return False
94+
95+
reg_value = int(reset_status_raw, 16)
96+
bin_format = bin(reg_value)[2:].zfill(32)
97+
return bin_format[::-1][self._index] == '0'
98+
99+
def get_presence(self):
100+
"""
101+
Retrieves the presence of the PSU
102+
Returns:
103+
bool: True if PSU is present, False if not
104+
"""
105+
presence_status_raw = self._api_helper.read_txt_file(
106+
self.PRS_PATH).rstrip()
107+
if not presence_status_raw:
108+
return False
109+
110+
content = presence_status_raw.rstrip()
111+
reg_value = int(content, 16)
112+
113+
# Determind if port_num start from 1 or 0
114+
bit_index = self._index
115+
116+
# Mask off the bit corresponding to our port
117+
mask = (1 << bit_index)
118+
119+
# ModPrsL is active low
120+
if reg_value & mask == 0:
121+
return True
122+
123+
return False
124+
125+
def get_lpmode(self):
126+
"""
127+
Retrieves the lpmode (low power mode) status of this SFP
128+
Returns:
129+
A Boolean, True if lpmode is enabled, False if disabled
130+
"""
131+
try:
132+
reg_file = open(self.LP_PATH, "r")
133+
content = reg_file.readline().rstrip()
134+
except IOError as e:
135+
print("Error: unable to open file: %s" % str(e))
136+
return False
137+
138+
# content is a string containing the hex representation of the register
139+
reg_value = int(content, 16)
140+
141+
# Determind if port_num start from 1 or 0
142+
bit_index = self._index
143+
144+
# Mask off the bit corresponding to our port
145+
mask = (1 << bit_index)
146+
147+
# LPMode is active high
148+
if reg_value & mask == 0:
149+
return False
150+
151+
return True
152+
153+
def reset(self):
154+
"""
155+
Reset SFP and return all user module settings to their default srate.
156+
Returns:
157+
A boolean, True if successful, False if not
158+
"""
159+
# Check for invalid port_num
160+
161+
try:
162+
reg_file = open(self.RESET_PATH, "r+")
163+
except IOError as e:
164+
print("Error: unable to open file: %s" % str(e))
165+
return False
166+
167+
content = reg_file.readline().rstrip()
168+
169+
# File content is a string containing the hex representation of the
170+
# register
171+
reg_value = int(content, 16)
172+
173+
# Determind if port_num start from 1 or 0
174+
bit_index = self._index
175+
176+
# Mask off the bit corresponding to our port
177+
mask = (1 << bit_index)
178+
179+
# ResetL is active low
180+
reg_value = reg_value & ~mask
181+
182+
# Convert our register value back to a hex string and write back
183+
reg_file.seek(0)
184+
reg_file.write(hex(reg_value).rstrip('L'))
185+
reg_file.close()
186+
187+
# Sleep 1 second to allow it to settle
188+
time.sleep(1)
189+
190+
# Flip the bit back high and write back to the register
191+
# to take port out of reset
192+
try:
193+
reg_file = open(self.RESET_PATH, "w")
194+
except IOError as e:
195+
print("Error: unable to open file: %s" % str(e))
196+
return False
197+
198+
reg_value = reg_value | mask
199+
reg_file.seek(0)
200+
reg_file.write(hex(reg_value).rstrip('L'))
201+
reg_file.close()
202+
203+
return True
204+
205+
def set_lpmode(self, lpmode):
206+
"""
207+
Sets the lpmode (low power mode) of SFP
208+
Args:
209+
lpmode: A Boolean, True to enable lpmode, False to disable it
210+
Note : lpmode can be overridden by set_power_override
211+
Returns:
212+
A boolean, True if lpmode is set successfully, False if not
213+
"""
214+
try:
215+
reg_file = open(self.LP_PATH, "r+")
216+
except IOError as e:
217+
print("Error: unable to open file: %s" % str(e))
218+
return False
219+
220+
content = reg_file.readline().rstrip()
221+
222+
# content is a string containing the hex representation of the register
223+
reg_value = int(content, 16)
224+
225+
# Determind if port_num start from 1 or 0
226+
bit_index = self._index
227+
228+
# Mask off the bit corresponding to our port
229+
mask = (1 << bit_index)
230+
# LPMode is active high; set or clear the bit accordingly
231+
reg_value = reg_value | mask if lpmode else reg_value & ~mask
232+
233+
# Convert our register value back to a hex string and write back
234+
content = hex(reg_value).strip('L')
235+
236+
reg_file.seek(0)
237+
reg_file.write(content)
238+
reg_file.close()
239+
240+
return True
241+
242+
def get_error_description(self):
243+
"""
244+
Retrives the error descriptions of the SFP module
245+
Returns:
246+
String that represents the current error descriptions of
247+
vendor specific errors
248+
In case there are multiple errors, they should be joined by '|',
249+
like: "Bad EEPROM|Unsupported cable"
250+
"""
251+
if self.sfp_type == "QSFP_DD":
252+
return super().get_error_description()
253+
254+
if not self.get_presence():
255+
return self.SFP_STATUS_UNPLUGGED
256+
return self.SFP_STATUS_OK
257+
258+
def get_position_in_parent(self):
259+
return self._index
260+
261+
def get_index(self):
262+
"""
263+
Retrieves current sfp index
264+
Returns:
265+
A int value, sfp index
266+
"""
267+
return self._index
268+
269+
def is_replaceable(self):
270+
return True

0 commit comments

Comments
 (0)