Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DellEMC: Fix z9332f low power mode issue #8693

Merged
merged 10 commits into from
Oct 8, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 114 additions & 24 deletions device/dell/x86_64-dellemc_z9332f_d1508-r0/plugins/sfputil.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
#
# Platform-specific SFP transceiver interface for SONiC
#

try:
import struct
import sys
import getopt
import time
import select
import io
from sonic_sfp.sfputilbase import SfpUtilBase
from os import *
from mmap import *
Expand All @@ -19,6 +18,25 @@
# from xcvrd
SFP_STATUS_REMOVED = '0'
SFP_STATUS_INSERTED = '1'
MEDIA_TYPE_OFFSET = 0
MEDIA_TYPE_WIDTH = 1
QSFP_DD_MODULE_ENC_OFFSET = 3
QSFP_DD_MODULE_ENC_WIDTH = 1

SFP_TYPE_LIST = [
'03' # SFP/SFP+/SFP28 and later
]
QSFP_TYPE_LIST = [
'0c', # QSFP
'0d', # QSFP+ or later
'11' # QSFP28 or later
]
QSFP_DD_TYPE_LIST = [
'18' #QSFP_DD Type
]
OSFP_TYPE_LIST=[
'19' # OSFP 8X Type
]


class SfpUtil(SfpUtilBase):
Expand Down Expand Up @@ -87,18 +105,77 @@ def qsfp_ports(self):
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping

def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes):
eeprom_raw = []
try:
eeprom = io.open(eeprom_path, mode="rb", buffering=0)
except IOError:
return None

for i in range(0, num_bytes):
eeprom_raw.append("0x00")

try:
eeprom.seek(offset)
raw = eeprom.read(num_bytes)
except IOError:
eeprom.close()
return None

try:
if isinstance(raw , str):
for n in range(0, num_bytes):
eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2)
else:
for n in range(0, num_bytes):
eeprom_raw[n] = hex(raw[n])[2:].zfill(2)

except (OSError, IOError):
eeprom.close()
return None

eeprom.close()
return eeprom_raw

def _write_eeprom_bytes(self, eeprom_path, offset, num_bytes, value):
try:
with io.open(eeprom_path, mode='r+b', buffering=0) as f:
f.seek(offset)
f.write(value[0:num_bytes])
except (OSError, IOError):
return False
return True


def get_media_type(self, port_num):
"""
Reads optic eeprom byte to determine media type inserted
"""
eeprom_raw = []
eeprom_raw = self._read_eeprom_bytes(self.port_to_eeprom_mapping[port_num], MEDIA_TYPE_OFFSET,
MEDIA_TYPE_WIDTH)
if eeprom_raw is not None:
if eeprom_raw[0] in SFP_TYPE_LIST:
sfp_type = 'SFP'
elif eeprom_raw[0] in QSFP_TYPE_LIST:
sfp_type = 'QSFP'
elif eeprom_raw[0] in QSFP_DD_TYPE_LIST:
sfp_type = 'QSFP_DD'
else:
#Set native port type if EEPROM type is not recognized/readable
sfp_type = 'QSFP_DD'
else:
sfp_type = 'QSFP_DD'

return sfp_type

def pci_mem_read(self, mm, offset):
mm.seek(offset)
read_data_stream = mm.read(4)
reg_val = struct.unpack('I', read_data_stream)
mem_val = str(reg_val)[1:-2]
# print "reg_val read:%x"%reg_val
return mem_val
return mm.read_byte()

def pci_mem_write(self, mm, offset, data):
mm.seek(offset)
# print "data to write:%x"%data
mm.write(struct.pack('I', data))
mm.write_byte(data)

def pci_set_value(self, resource, val, offset):
fd = open(resource, O_RDWR)
Expand Down Expand Up @@ -181,23 +258,32 @@ def get_low_power_mode(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
if port_num > self.PORTS_IN_BLOCK:
return False
if self.get_media_type(port_num) == 'QSFP_DD':
lpmode = self._read_eeprom_bytes(self.port_to_eeprom_mapping[port_num], QSFP_DD_MODULE_ENC_OFFSET,
QSFP_DD_MODULE_ENC_WIDTH)
if lpmode is not None:
if int(lpmode[0])>>1 == 1:
return True
return False
else:
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)

# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
# Absence of status throws error
if (status == ""):
return False

status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
reg_value = int(status)

# Absence of status throws error
if (reg_value == ""):
return False
# Mask off 4th bit for presence
mask = (1 << 6)

# Mask off 4th bit for presence
mask = (1 << 6)

# LPMode is active high
if reg_value & mask == 0:
return False
# LPMode is active high
if reg_value & mask == 0:
return False

return True

Expand All @@ -206,10 +292,10 @@ def set_low_power_mode(self, port_num, lpmode):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False

if port_num > self.PORTS_IN_BLOCK:
aravindmani-1 marked this conversation as resolved.
Show resolved Hide resolved
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)

status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)

Expand All @@ -223,12 +309,16 @@ def set_low_power_mode(self, port_num, lpmode):
# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
write_val = 0x10
else:
reg_value = reg_value & ~mask
write_val = 0x0

# Convert our register value back to a hex string and write back
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)

if self.get_media_type(port_num) == 'QSFP_DD':
self._write_eeprom_bytes(self.port_to_eeprom_mapping[port_num], 26, 1, bytearray([write_val]))
return True

def reset(self, port_num):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import re
import time
import subprocess
import struct
import mmap
from sonic_platform_base.sfp_base import SfpBase
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
Expand Down Expand Up @@ -60,6 +59,8 @@
QSFP_DD_APP1_ADV_WIDTH = 32
QSFP_DD_APP2_ADV_OFFSET = 351
QSFP_DD_APP2_ADV_WIDTH = 28
QSFP_DD_MODULE_ENC_OFFSET = 3
QSFP_DD_MODULE_ENC_WIDTH = 1

QSFP_INFO_OFFSET = 128
QSFP_DOM_OFFSET = 0
Expand Down Expand Up @@ -311,16 +312,12 @@ def _strip_unit_from_str(self, value_str):

def pci_mem_read(self, mm, offset):
mm.seek(offset)
read_data_stream = mm.read(4)
reg_val = struct.unpack('I', read_data_stream)
mem_val = str(reg_val)[1:-2]
# print "reg_val read:%x"%reg_val
return mem_val
return mm.read_byte()

def pci_mem_write(self, mm, offset, data):
mm.seek(offset)
# print "data to write:%x"%data
mm.write(struct.pack('I', data))
mm.write_byte(data)

def pci_set_value(self, resource, val, offset):
fd = os.open(resource, os.O_RDWR)
Expand All @@ -338,6 +335,15 @@ def pci_get_value(self, resource, offset):
os.close(fd)
return val

def _write_eeprom_bytes(self, offset, num_bytes, value):
try:
with open(self.eeprom_path, mode='r+b', buffering=0) as f:
f.seek(offset)
f.write(value[0:num_bytes])
except (OSError, IOError):
return False
return True

def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes):
eeprom_raw = []
try:
Expand Down Expand Up @@ -993,7 +999,13 @@ def get_lpmode(self):
"""
lpmode_state = False
try:
if self.sfp_type.startswith('QSFP'):
if self.sfp_type == 'QSFP_DD':
aravindmani-1 marked this conversation as resolved.
Show resolved Hide resolved
lpmode = self._read_eeprom_bytes(self.eeprom_path, QSFP_DD_MODULE_ENC_OFFSET, QSFP_DD_MODULE_ENC_WIDTH)
if lpmode is not None:
if int(lpmode[0])>>1 == 1:
return True
return False
else:
# Port offset starts with 0x4000
port_offset = 16384 + ((self.index-1) * 16)

Expand All @@ -1004,7 +1016,8 @@ def get_lpmode(self):
mask = (1 << 6)

lpmode_state = (reg_value & mask)
except ValueError: pass
except ValueError:
pass
return lpmode_state

def get_power_override(self):
Expand Down Expand Up @@ -1230,7 +1243,7 @@ def set_lpmode(self, lpmode):
Sets the lpmode(low power mode) of this SFP
"""
try:
if self.port_type == 'QSFP_DD':
if self.sfp_type.startswith('QSFP'):
# Port offset starts with 0x4000
port_offset = 16384 + ((self.index-1) * 16)

Expand All @@ -1243,11 +1256,15 @@ def set_lpmode(self, lpmode):
# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
write_val = 0x10
else:
reg_value = reg_value & ~mask
write_val = 0x0

# Convert our register value back to a hex string and write back
self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
prgeor marked this conversation as resolved.
Show resolved Hide resolved
if self.sfp_type == 'QSFP_DD':
self._write_eeprom_bytes(26, 1, bytearray([write_val]))
except ValueError:
return False
return True
Expand Down