Skip to content

Commit 357115b

Browse files
authored
add cpo bailly xcvr cmis (#689)
<!-- Provide a general summary of your changes in the Title above --> #### Description <!-- Describe your changes in detail --> Add CPO Bailly-related CMIS APIs/MEM maps/Code/Fields as well as the CPO management base class #### Motivation and Context <!-- Why is this change required? What problem does it solve? If this pull request closes/resolves an open Issue, make sure you include the text "fixes #xxxx", "closes #xxxx" or "resolves #xxxx" here --> Run Bailly using the community framework #### How Has This Been Tested? <!-- Please describe in detail how you tested your changes. Include details of your testing environment, and the tests you ran to see how your change affects other areas of the code, etc. --> Signed-off-by: Sonic Build Admin <sonicbld@microsoft.com> #### Additional Information (Optional)
1 parent 4b63470 commit 357115b

12 files changed

Lines changed: 1078 additions & 0 deletions

File tree

setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,20 @@
4343
'sonic_platform_base.sonic_xcvr',
4444
'sonic_platform_base.sonic_xcvr.fields',
4545
'sonic_platform_base.sonic_xcvr.fields.public',
46+
'sonic_platform_base.sonic_xcvr.fields.bailly',
4647
'sonic_platform_base.sonic_xcvr.mem_maps',
4748
'sonic_platform_base.sonic_xcvr.mem_maps.public',
49+
'sonic_platform_base.sonic_xcvr.mem_maps.bailly',
4850
'sonic_platform_base.sonic_xcvr.mem_maps.public.cmis',
4951
'sonic_platform_base.sonic_xcvr.mem_maps.public.cmis.pages',
5052
'sonic_platform_base.sonic_xcvr.mem_maps.public.cmis.elsfp',
5153
'sonic_platform_base.sonic_xcvr.mem_maps.public.cmis.elsfp.pages',
5254
'sonic_platform_base.sonic_xcvr.api',
5355
'sonic_platform_base.sonic_xcvr.api.public',
56+
'sonic_platform_base.sonic_xcvr.api.bailly',
5457
'sonic_platform_base.sonic_xcvr.codes',
5558
'sonic_platform_base.sonic_xcvr.codes.public',
59+
'sonic_platform_base.sonic_xcvr.codes.bailly',
5660
'sonic_platform_base.sonic_xcvr.utils',
5761
'sonic_platform_base.sonic_xcvr.api.credo',
5862
'sonic_platform_base.sonic_xcvr.mem_maps.credo',

sonic_platform_base/sonic_xcvr/api/bailly/__init__.py

Whitespace-only changes.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
"""
2+
bailly_api.py
3+
4+
Implementation of Micas Bailly CPO specific in addition to the CMIS specification.
5+
"""
6+
from ..public.cmis import CmisApi
7+
from ...fields.bailly import bailly_consts
8+
9+
class BaillyApi(CmisApi):
10+
def __init__(self, xcvr_eeprom):
11+
super(BaillyApi, self).__init__(xcvr_eeprom)
12+
13+
def get_dpinit_pending(self):
14+
'''
15+
Bailly not supported, return fake value.
16+
'''
17+
dpinit_pending_dict = {}
18+
for lane in range(self.NUM_CHANNELS):
19+
key = "DPInitPending{}".format(lane + 1)
20+
dpinit_pending_dict[key] = True
21+
return dpinit_pending_dict
22+
23+
def get_active_apsel_hostlane(self):
24+
'''
25+
Bailly not supported Deinit, if it is deinit return fake value.
26+
'''
27+
has_zero = False
28+
current_map = {}
29+
for lane in range(self.NUM_CHANNELS):
30+
lane_key = 'ActiveAppSelLane{}'.format(lane + 1)
31+
app_lane = self.get_application(lane)
32+
current_map[lane_key] = app_lane
33+
if app_lane == 0:
34+
has_zero = True
35+
36+
if has_zero:
37+
return current_map
38+
else:
39+
normal = super().get_active_apsel_hostlane()
40+
return normal
41+
def _format_revision(self, revision):
42+
if revision is None:
43+
return None
44+
return "{}.{}".format((revision >> 4) & 0xf, revision & 0xf)
45+
46+
def get_transceiver_info(self):
47+
info = super().get_transceiver_info()
48+
if info is None:
49+
return None
50+
51+
els_info = self.get_els_info()
52+
cpo_info = els_info.get("cpo_info")
53+
vendor_info = els_info.get("vendor_info")
54+
laser_power_mode = els_info.get("laser_power_mode")
55+
if cpo_info is None and vendor_info is None and laser_power_mode is None:
56+
return info
57+
58+
if cpo_info is not None:
59+
info.update({
60+
"els_identifier": cpo_info.get(bailly_consts.CPO_IDENTIFIER),
61+
"els_revision": self._format_revision(cpo_info.get(bailly_consts.CPO_REVISION)),
62+
"els_laser_grid_and_count": cpo_info.get(bailly_consts.LASER_GRID_AND_COUNT),
63+
"els_laser_wavelength_grid": cpo_info.get(bailly_consts.LASER_WAVELENGTH_GRID),
64+
"els_laser_count": cpo_info.get(bailly_consts.LASER_COUNT),
65+
})
66+
67+
if vendor_info is not None:
68+
info.update({
69+
"els_vendor_name": self._strip_str(
70+
vendor_info.get(bailly_consts.VENDOR_NAME_ASCII_FIELD)
71+
),
72+
"els_vendor_oui": vendor_info.get(bailly_consts.VENDOR_OUI_HEX_FIELD),
73+
"els_vendor_pn": self._strip_str(
74+
vendor_info.get(bailly_consts.VENDOR_PART_NUMBER_ASCII_FIELD)
75+
),
76+
"els_vendor_rev": self._strip_str(
77+
vendor_info.get(bailly_consts.VENDOR_REVISION_ASCII_FIELD)
78+
),
79+
"els_vendor_sn": self._strip_str(
80+
vendor_info.get(bailly_consts.VENDOR_SERIAL_NUMBER_ASCII_FIELD)
81+
),
82+
"els_date_code": self._strip_str(
83+
vendor_info.get(bailly_consts.DATE_CODE_FIELD)
84+
),
85+
"els_max_power": vendor_info.get(bailly_consts.MAX_POWER_CONSUMPTION_FIELD),
86+
})
87+
88+
if laser_power_mode is not None:
89+
info.update({
90+
"els_laser_power_mode_control": laser_power_mode.get(
91+
bailly_consts.LASER_POWER_MODE_CONTROL_BITS_FIELD
92+
),
93+
})
94+
95+
return info
96+
97+
def get_els_vendor_info(self):
98+
return self.xcvr_eeprom.read(bailly_consts.CPO_VENDOR_INFO_FIELD)
99+
100+
def get_els_info(self):
101+
return {
102+
"cpo_info": self.xcvr_eeprom.read(bailly_consts.CPO_INFO_FIELD),
103+
"vendor_info": self.get_els_vendor_info(),
104+
"laser_power_mode": self.xcvr_eeprom.read(bailly_consts.LASER_POWER_MODE_CONTROL_FIELD),
105+
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
"""
2+
cpo_optoe_base.py
3+
4+
Platform-independent class with which to interact with a cpo module
5+
in SONiC
6+
"""
7+
import abc
8+
import os
9+
import json
10+
from .sfp_optoe_base import SfpOptoeBase
11+
from sonic_py_common.device_info import get_platform, get_path_to_platform_dir
12+
13+
CPO_JSON_FILE = "cpo.json"
14+
def get_cpo_json_data():
15+
"""
16+
Retrieve the data from cpo.json file
17+
18+
Returns:
19+
A dictionary containing the key/value pairs as found in the cpo.json file
20+
"""
21+
platform = get_platform()
22+
if not platform:
23+
return None
24+
25+
platform_path = get_path_to_platform_dir()
26+
if not platform_path:
27+
return None
28+
29+
platform_json = os.path.join(platform_path, CPO_JSON_FILE)
30+
if not os.path.isfile(platform_json):
31+
return None
32+
33+
try:
34+
with open(platform_json, 'r') as f:
35+
cpo_data = json.loads(f.read())
36+
return cpo_data
37+
except (json.JSONDecodeError, IOError, TypeError, ValueError):
38+
return None
39+
40+
class CpoOptoeBase(SfpOptoeBase):
41+
def __init__(self):
42+
super().__init__()
43+
self._port_id = -1
44+
self._oe_bank_id = -1
45+
self._oe_id = -1
46+
self._els_id = -1
47+
self._els_bank_id = -1
48+
49+
def get_oe_eeprom_path(self):
50+
oes_cfg = self.get_oes_config() or {}
51+
cpo_bus = oes_cfg.get("oe_cmis_path")
52+
return (cpo_bus + "eeprom") if cpo_bus else None
53+
54+
def get_eeprom_path(self):
55+
return self.get_oe_eeprom_path()
56+
57+
def get_oes_config(self):
58+
key = f"oe{self._oe_id}"
59+
cpo_data = get_cpo_json_data() or {}
60+
return (cpo_data.get("oes") or {}).get(key)
61+
62+
def get_elss_config(self):
63+
key = f"els{self._els_id}"
64+
cpo_data = get_cpo_json_data() or {}
65+
return (cpo_data.get("elss") or {}).get(key)
66+
67+
def read_eeprom(self, offset, num_bytes):
68+
sys_path = self.get_eeprom_path()
69+
if not sys_path:
70+
return None
71+
try:
72+
with open(sys_path, mode='rb', buffering=0) as f:
73+
f.seek(offset)
74+
return bytearray(f.read(num_bytes))
75+
except (OSError, IOError, TypeError):
76+
return None
77+
78+
def write_eeprom(self, offset, num_bytes, write_buffer):
79+
sys_path = self.get_eeprom_path()
80+
if not sys_path:
81+
return False
82+
try:
83+
with open(sys_path, mode='r+b', buffering=0) as f:
84+
f.seek(offset)
85+
f.write(write_buffer[0:num_bytes])
86+
except (OSError, IOError, TypeError):
87+
return False
88+
return True
89+
90+
def get_els_presence(self):
91+
try:
92+
elss_cfg = self.get_elss_config() or {}
93+
els_presence = elss_cfg.get("els_presence") or {}
94+
95+
els_presence_file = els_presence.get("presence_file")
96+
presence_offset = int(els_presence.get("presence_offset", "0"), 16)
97+
presence_len = int(els_presence.get("presence_len", 0))
98+
presence_bit = int(els_presence.get("presence_bit", 0))
99+
presence_value = int(els_presence.get("presence_value", 1))
100+
101+
if not els_presence_file or presence_len <= 0:
102+
return False
103+
104+
with open(els_presence_file, mode='rb', buffering=0) as f:
105+
f.seek(presence_offset)
106+
raw = bytearray(f.read(presence_len))
107+
int_value = int.from_bytes(raw, byteorder='little')
108+
return ((int_value >> presence_bit) & 1) == presence_value
109+
except (OSError, IOError, TypeError, ValueError, AttributeError):
110+
return False
111+
112+
def get_presence(self):
113+
return self.get_els_presence()
114+
115+
def get_els_base_page(self):
116+
elss_cfg = self.get_elss_config() or {}
117+
return int(elss_cfg.get("base_page", 0))
118+
119+
def get_oe_bank_id(self):
120+
return self._oe_bank_id
121+
def get_oe_id(self):
122+
return self._oe_id
123+
def get_els_bank_id(self):
124+
return self._els_bank_id
125+
def get_els_id(self):
126+
return self._els_id
127+
128+
@abc.abstractmethod
129+
def check_fiber_dirty(self):
130+
"""
131+
Check whether the fiber is dirty. True:check ok; False: check failed
132+
"""
133+
raise NotImplementedError
134+
135+
@abc.abstractmethod
136+
def check_calibration(self):
137+
"""
138+
Check whether the calibration such as oe power sufficient. True:check ok; False: check failed
139+
"""
140+
raise NotImplementedError
141+
142+
@abc.abstractmethod
143+
def is_els_power_sufficient(self):
144+
"""
145+
Check whether els power sufficient.
146+
"""
147+
raise NotImplementedError
148+
149+
@abc.abstractmethod
150+
def is_calibration_checked(self):
151+
"""
152+
Check whether the calibration such as oe power sufficient detection​ has been completed.
153+
"""
154+
raise NotImplementedError
155+
156+
@abc.abstractmethod
157+
def is_fiber_checked(self):
158+
"""
159+
Check whether the fiber detection​ has been completed.
160+
"""
161+
raise NotImplementedError
162+
163+
@abc.abstractmethod
164+
def is_els_tx_on(self):
165+
"""
166+
Check the ELS TX​ status to see if it is emitting light normally.
167+
"""
168+
raise NotImplementedError
169+
170+
@abc.abstractmethod
171+
def is_els_tx_enabled(self):
172+
"""
173+
Check whether the ELS TX enable​ has been set.
174+
"""
175+
raise NotImplementedError
176+

sonic_platform_base/sonic_xcvr/codes/bailly/__init__.py

Whitespace-only changes.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from ..public.cmis import CmisCodes
2+
3+
class BaillyCodes(CmisCodes):
4+
# Vendor specific implementation to be added here
5+
XCVR_IDENTIFIERS = {
6+
**CmisCodes.XCVR_IDENTIFIERS,
7+
128: 'CPO Bailly',
8+
}
9+
10+
XCVR_IDENTIFIER_ABBRV = {
11+
**CmisCodes.XCVR_IDENTIFIER_ABBRV,
12+
128: 'QSFP-DD',
13+
}
14+
15+
HOST_ELECTRICAL_INTERFACE = {
16+
**CmisCodes.HOST_ELECTRICAL_INTERFACE,
17+
253: 'Bailly-Reserved-1',
18+
254: 'Bailly-Reserved-2',
19+
}
20+
21+
SM_MEDIA_INTERFACE = {
22+
**CmisCodes.SM_MEDIA_INTERFACE,
23+
193: 'Bailly-800G-2xFR4',
24+
253: 'Bailly-Reserved-LC-1',
25+
254: 'Bailly-Reserved-LC-2',
26+
}
27+
28+
LASER_WAVELENGTH_GRID = {
29+
0: "CWDM4",
30+
1: "DR4",
31+
}
32+
33+
LASER_COUNT = {
34+
code: code + 1 for code in range(16)
35+
}
36+
37+
POWER_MODE = {
38+
0: "High power mode",
39+
1: "Low power mode",
40+
}
41+
42+
INTERRUPT_STATUS = {
43+
0: "Interrupt event occurred",
44+
1: "Interrupt event cleared",
45+
}
46+
47+
LASER_DISABLE_CONTROL = {
48+
0: "Enable",
49+
1: "Disable",
50+
}
51+
52+
LASER_ACTIVE_STATUS = {
53+
0: "Inactive",
54+
1: "Active",
55+
}
56+
57+
LASER_POWER_MODE_ENABLE = {
58+
0: "Disable",
59+
1: "Enable",
60+
}
61+
62+
MAX_BANKS_SUPPORTED = {
63+
**CmisCodes.MAX_BANKS_SUPPORTED,
64+
3: 8,
65+
}
66+

sonic_platform_base/sonic_xcvr/fields/bailly/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)