Skip to content

Commit 7aadc13

Browse files
authored
Merge pull request sonic-net#77 from prgeor/amph-bp
Support for Custom Amphenol 800G Backplane catridge (sonic-net#555)
2 parents 8ce4e83 + b1ab4e6 commit 7aadc13

File tree

12 files changed

+302
-61
lines changed

12 files changed

+302
-61
lines changed

sonic_platform_base/sonic_xcvr/api/amphenol/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
"""
2+
Custom API for Amphenol 800G Backplane Cartridge
3+
"""
4+
import copy
5+
from ...fields import consts
6+
from ..public.cmis import CmisApi
7+
8+
AMPH_BACKPLANE_INFO_DICT = {
9+
"type": "N/A",
10+
"type_abbrv_name": "N/A",
11+
"hardware_rev": "N/A",
12+
"serial": "N/A",
13+
"cable_length": "N/A",
14+
"manufacturer": "N/A", # Vendor Name
15+
"model": "N/A", # Vendor Part Number
16+
"vendor_date": "N/A",
17+
"vendor_oui": "N/A",
18+
"vendor_rev": "N/A",
19+
"application_advertisement": "N/A",
20+
"host_electrical_interface": "N/A",
21+
"host_lane_count": "N/A",
22+
"cable_type": "N/A",
23+
"cmis_rev": "N/A",
24+
"specification_compliance": "N/A",
25+
"slot_id": "unknown"
26+
}
27+
28+
class AmphBackplaneImpl(CmisApi):
29+
"""
30+
Custom API for Amphenol 800G Backplane Catridge
31+
"""
32+
def __init__(self, xcvr_eeprom):
33+
super(AmphBackplaneImpl, self).__init__(xcvr_eeprom)
34+
35+
def get_slot_id(self):
36+
"""
37+
Get the slot id
38+
"""
39+
slot = self.xcvr_eeprom.read(consts.CARTRDIGE_SLOT_ID)
40+
if slot is None:
41+
return "N/A"
42+
return slot
43+
44+
def get_transceiver_info(self):
45+
admin_info = self.xcvr_eeprom.read(consts.ADMIN_INFO_FIELD)
46+
if admin_info is None:
47+
return None
48+
49+
xcvr_info = copy.deepcopy(AMPH_BACKPLANE_INFO_DICT)
50+
xcvr_info.update({
51+
"type": admin_info[consts.ID_FIELD],
52+
"type_abbrv_name": admin_info[consts.ID_ABBRV_FIELD],
53+
"hardware_rev": self.get_module_hardware_revision(),
54+
"cable_length": float(admin_info[consts.LENGTH_ASSEMBLY_FIELD]),
55+
"application_advertisement": str(self.get_application_advertisement()) \
56+
if len(self.get_application_advertisement()) > 0 else 'N/A',
57+
"host_electrical_interface": self.get_host_electrical_interface(),
58+
"host_lane_count": self.get_host_lane_count(),
59+
"host_lane_assignment_option": self.get_host_lane_assignment_option(),
60+
"cable_type": self.get_cable_length_type(),
61+
"cmis_rev": self.get_cmis_rev(),
62+
"specification_compliance": self.get_module_media_type(),
63+
"vdm_supported": self.is_transceiver_vdm_supported()
64+
})
65+
66+
appl_adv = self.get_application_advertisement()
67+
if len(appl_adv) > 0:
68+
xcvr_info["application_advertisement"] = str(appl_adv)
69+
70+
# Vendor specific fields
71+
xcvr_info.update({
72+
"serial": admin_info[consts.VENDOR_SERIAL_NO_FIELD],
73+
"manufacturer": admin_info[consts.VENDOR_NAME_FIELD],
74+
"model": admin_info[consts.VENDOR_PART_NO_FIELD],
75+
"vendor_date": admin_info[consts.VENDOR_DATE_FIELD],
76+
"vendor_oui": admin_info[consts.VENDOR_OUI_FIELD],
77+
"vendor_rev": self.get_vendor_rev(),
78+
"slot_id": self.get_slot_id(),
79+
})
80+
return xcvr_info
81+

sonic_platform_base/sonic_xcvr/codes/amphenol/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from ..public.cmis import CmisCodes
2+
3+
class AmphBackplaneCodes(CmisCodes):
4+
CARTRDIGE_SLOT_ID = {
5+
0x1 : "1",
6+
0x2 : "2",
7+
0x3 : "3",
8+
0x4 : "4"
9+
}

sonic_platform_base/sonic_xcvr/codes/public/sff8024.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class Sff8024(XcvrCodes):
3838
27: 'DSFP Dual Small Form Factor Pluggable Transceiver',
3939
28: 'x4 MiniLink/OcuLink',
4040
29: 'x8 MiniLink',
41-
30: 'QSFP+ or later with CMIS'
41+
30: 'QSFP+ or later with CMIS',
42+
126: 'Backplane Cartridge',
4243
}
4344

4445
XCVR_IDENTIFIER_ABBRV = {

sonic_platform_base/sonic_xcvr/fields/consts.py

+1
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,4 @@
496496
#VENDOR SPECIFIC
497497
VENDOR_CUSTOM = "VendorCustom"
498498
TARGET_MODE = "TargetMode"
499+
CARTRDIGE_SLOT_ID = "CartridgeSlotID"

sonic_platform_base/sonic_xcvr/mem_maps/amphenol/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
Custom memory map for Amphenol 800G Backplane connector
3+
"""
4+
5+
from ...mem_maps.public.cmis import CmisFlatMemMap
6+
from ...fields.xcvr_field import (
7+
NumberRegField,
8+
RegGroupField,
9+
CodeRegField
10+
)
11+
from ...fields import consts
12+
13+
class AmphBackplaneMemMap(CmisFlatMemMap):
14+
def __init__(self, codes):
15+
super(AmphBackplaneMemMap, self).__init__(codes)
16+
17+
self.SLOT_ID = CodeRegField(consts.CARTRDIGE_SLOT_ID, self.getaddr(0x0, 203),
18+
self.codes.CARTRDIGE_SLOT_ID)

sonic_platform_base/sonic_xcvr/mem_maps/public/cmis.py

+14-4
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,20 @@
1818
from ...fields import consts
1919
from ...fields.public.cmis import CableLenField
2020

21-
class CmisMemMap(XcvrMemMap):
21+
class CmisFlatMemMap(XcvrMemMap):
22+
"""
23+
Memory map for CMIS flat memory (Lower page and Upper page 0h ONLY)
24+
"""
2225
def __init__(self, codes):
23-
super(CmisMemMap, self).__init__(codes)
26+
super(CmisFlatMemMap, self).__init__(codes)
2427

2528
self.MGMT_CHARACTERISTICS = RegGroupField(consts.MGMT_CHAR_FIELD,
2629
NumberRegField(consts.MGMT_CHAR_MISC_FIELD, self.getaddr(0x0, 2),
2730
RegBitField(consts.FLAT_MEM_FIELD, 7)
2831
)
2932
)
3033

31-
# Should contain ONLY Lower page fields
34+
# This memmap should contain ONLY Lower page 00h and upper page 00h fields
3235
self.ADMIN_INFO = RegGroupField(consts.ADMIN_INFO_FIELD,
3336
CodeRegField(consts.ID_FIELD, self.getaddr(0x0, 0), self.codes.XCVR_IDENTIFIERS),
3437
CodeRegField(consts.ID_ABBRV_FIELD, self.getaddr(0x0, 128), self.codes.XCVR_IDENTIFIER_ABBRV),
@@ -109,7 +112,14 @@ def __init__(self, codes):
109112
NumberRegField(consts.ACTIVE_FW_MINOR_REV, self.getaddr(0x0, 40), format="B", size=1),
110113
)
111114

112-
# Should contain ONLY upper page fields
115+
def getaddr(self, page, offset, page_size=128):
116+
return page * page_size + offset
117+
118+
class CmisMemMap(CmisFlatMemMap):
119+
def __init__(self, codes):
120+
super(CmisMemMap, self).__init__(codes)
121+
122+
# This memmap should contain ONLY upper page >= 01h fields
113123
self.ADVERTISING = RegGroupField(consts.ADVERTISING_FIELD,
114124
NumberRegField(consts.INACTIVE_FW_MAJOR_REV, self.getaddr(0x1, 128), format="B", size=1),
115125
NumberRegField(consts.INACTIVE_FW_MINOR_REV, self.getaddr(0x1, 129), format="B", size=1),

sonic_platform_base/sonic_xcvr/xcvr_api_factory.py

+57-54
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919

2020
from .api.innolight.fr_800g import CmisFr800gApi
2121

22+
from .api.amphenol.backplane import AmphBackplaneImpl
23+
from .mem_maps.amphenol.backplane import AmphBackplaneMemMap
24+
from .codes.amphenol.backplane import AmphBackplaneCodes
25+
2226
from .codes.public.sff8436 import Sff8436Codes
2327
from .api.public.sff8436 import Sff8436Api
2428
from .mem_maps.public.sff8436 import Sff8436MemMap
@@ -70,60 +74,59 @@ def _get_vendor_part_num(self):
7074
return None
7175
vendor_pn = part_num.decode()
7276
return vendor_pn.strip()
73-
74-
def create_xcvr_api(self):
75-
# TODO: load correct classes from id_mapping file
76-
id = self._get_id()
77-
# QSFP-DD or OSFP
78-
if id == 0x18 or id == 0x19 or id == 0x1e:
79-
vendor_name = self._get_vendor_name()
80-
vendor_pn = self._get_vendor_part_num()
81-
if vendor_name == 'Credo' and vendor_pn in CREDO_800G_AEC_VENDOR_PN_LIST:
82-
codes = CmisAec800gCodes
83-
mem_map = CmisAec800gMemMap(CmisAec800gCodes)
84-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
85-
api = CmisAec800gApi(xcvr_eeprom)
86-
elif ('INNOLIGHT' in vendor_name and vendor_pn in INL_800G_VENDOR_PN_LIST) or \
87-
('EOPTOLINK' in vendor_name and vendor_pn in EOP_800G_VENDOR_PN_LIST):
88-
codes = CmisCodes
89-
mem_map = CmisMemMap(codes)
90-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
91-
api = CmisFr800gApi(xcvr_eeprom)
92-
else:
93-
codes = CmisCodes
94-
mem_map = CmisMemMap(codes)
95-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
96-
api = CmisApi(xcvr_eeprom)
9777

98-
if api.is_coherent_module():
99-
mem_map = CCmisMemMap(codes)
100-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
101-
api = CCmisApi(xcvr_eeprom)
102-
103-
# QSFP28
104-
elif id == 0x11:
105-
codes = Sff8636Codes
106-
mem_map = Sff8636MemMap(codes)
107-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
108-
api = Sff8636Api(xcvr_eeprom)
109-
# QSFP+
110-
elif id == 0x0D:
111-
revision_compliance = self._get_revision_compliance()
112-
if revision_compliance >= 3:
113-
codes = Sff8636Codes
114-
mem_map = Sff8636MemMap(codes)
115-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
116-
api = Sff8636Api(xcvr_eeprom)
117-
else:
118-
codes = Sff8436Codes
119-
mem_map = Sff8436MemMap(codes)
120-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
121-
api = Sff8436Api(xcvr_eeprom)
122-
elif id == 0x03:
123-
codes = Sff8472Codes
124-
mem_map = Sff8472MemMap(codes)
125-
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
126-
api = Sff8472Api(xcvr_eeprom)
78+
def _create_cmis_api(self):
79+
api = None
80+
vendor_name = self._get_vendor_name()
81+
vendor_pn = self._get_vendor_part_num()
82+
83+
if vendor_name == 'Credo' and vendor_pn in CREDO_800G_AEC_VENDOR_PN_LIST:
84+
api = self._create_api(CmisAec800gCodes, CmisAec800gMemMap, CmisAec800gApi)
85+
elif ('INNOLIGHT' in vendor_name and vendor_pn in INL_800G_VENDOR_PN_LIST) or \
86+
('EOPTOLINK' in vendor_name and vendor_pn in EOP_800G_VENDOR_PN_LIST):
87+
api = self._create_api(CmisCodes, CmisMemMap, CmisFr800gApi)
88+
12789
else:
128-
api = None
90+
api = self._create_api(CmisCodes, CmisMemMap, CmisApi)
91+
if api.is_coherent_module():
92+
api = self._create_api(CmisCodes, CCmisMemMap, CCmisApi)
12993
return api
94+
95+
def _create_qsfp_api(self):
96+
"""
97+
QSFP/QSFP+ API implementation
98+
"""
99+
revision_compliance = self._get_revision_compliance()
100+
if revision_compliance >= 3:
101+
return self._create_api(Sff8636Codes, Sff8636MemMap, Sff8636Api)
102+
else:
103+
return self._create_api(Sff8436Codes, Sff8436MemMap, Sff8436Api)
104+
105+
def _create_api(self, codes_class, mem_map_class, api_class):
106+
codes = codes_class
107+
mem_map = mem_map_class(codes)
108+
xcvr_eeprom = XcvrEeprom(self.reader, self.writer, mem_map)
109+
return api_class(xcvr_eeprom)
110+
111+
def create_xcvr_api(self):
112+
id = self._get_id()
113+
114+
# Instantiate various Optics implementation based upon their respective ID as per SFF8024
115+
id_mapping = {
116+
0x03: (self._create_api, (Sff8472Codes, Sff8472MemMap, Sff8472Api)),
117+
0x0D: (self._create_qsfp_api, ()),
118+
0x11: (self._create_api, (Sff8636Codes, Sff8636MemMap, Sff8636Api)),
119+
0x18: (self._create_cmis_api, ()),
120+
0x19: (self._create_cmis_api, ()),
121+
0x1b: (self._create_cmis_api, ()),
122+
0x1e: (self._create_cmis_api, ()),
123+
0x7e: (self._create_api, (AmphBackplaneCodes,
124+
AmphBackplaneMemMap, AmphBackplaneImpl)),
125+
}
126+
127+
# Check if the ID exists in the mapping
128+
if id in id_mapping:
129+
func, args = id_mapping[id]
130+
if isinstance(args, tuple):
131+
return func(*args)
132+
return None

sonic_platform_base/sonic_xcvr/xcvr_eeprom.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ def read_raw(self, offset, size, return_raw = False):
5454
data = struct.unpack("%dB" %size, raw_data)
5555
return data
5656

57-
5857
def write(self, field_name, value):
5958
"""
6059
Write a value to a field in EEPROM
@@ -90,4 +89,4 @@ def write_raw(self, offset, size, bytearray_data):
9089
Returns:
9190
Boolean, True if the write is successful and False otherwise
9291
"""
93-
return self.writer(offset, size, bytearray_data)
92+
return self.writer(offset, size, bytearray_data)

0 commit comments

Comments
 (0)