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-Z9264f: Interrupt based Optic OIR #2926

Merged
merged 1 commit into from
May 23, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
166 changes: 121 additions & 45 deletions device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
import getopt
import time
import select
from sonic_sfp.sfputilbase import SfpUtilBase
from os import *
from mmap import *
Expand All @@ -24,6 +25,10 @@ class SfpUtil(SfpUtilBase):
PORTS_IN_BLOCK = 64

BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0"
OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi"

oir_fd = -1
epoll = -1

_port_to_eeprom_mapping = {}

Expand All @@ -47,16 +52,16 @@ def port_to_eeprom_mapping(self):

def pci_mem_read(self, mm, offset):
mm.seek(offset)
read_data_stream=mm.read(4)
reg_val=struct.unpack('I',read_data_stream)
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

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(struct.pack('I', data))

def pci_set_value(self, resource, val, offset):
fd = open(resource, O_RDWR)
Expand All @@ -73,25 +78,23 @@ def pci_get_value(self, resource, offset):
mm.close()
close(fd)
return val

def init_global_port_presence(self):
for port_num in range(self.port_start, (self.port_end + 1)):
presence = self.get_presence(port_num)
if(presence):
self._global_port_pres_dict[port_num] = '1'
else:
self._global_port_pres_dict[port_num] = '0'

def __init__(self):
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"

for x in range(self.port_start, self.port_end + 1):
port_num = x + 1
self.port_to_eeprom_mapping[x] = eeprom_path.format(
port_num)
port_num = x + 1
self.port_to_eeprom_mapping[x] = eeprom_path.format(port_num)
port_num = 0
self.init_global_port_presence()

SfpUtilBase.__init__(self)

def get_presence(self, port_num):
Expand All @@ -100,13 +103,13 @@ def get_presence(self, port_num):
return False

# Port offset starts with 0x4004
port_offset = 16388 + ((port_num-1) * 16)
port_offset = 16388 + ((port_num-1) * 16)

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

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

# Absence of status throws error
if (reg_value == "" ):
if (reg_value == ""):
return False

# Mask off 4th bit for presence
Expand All @@ -124,14 +127,14 @@ def get_low_power_mode(self, port_num):
if port_num < self.port_start or port_num > self.port_end:
return False

# 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)
reg_value = int(status)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)

# Absence of status throws error
if (reg_value == "" ):
if (reg_value == ""):
return False

# Mask off 4th bit for presence
Expand All @@ -149,44 +152,44 @@ def set_low_power_mode(self, port_num, lpmode):
if port_num < self.port_start or port_num > self.port_end:
return False

# 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)
reg_value = int(status)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)

# Absence of status throws error
if (reg_value == "" ):
if (reg_value == ""):
return False

# Mask off 4th bit for presence
mask = (1 << 6)
# LPMode is active high; set or clear the bit accordingly

# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
else:
reg_value = reg_value & ~mask

# 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)
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)

return True

def reset(self, port_num):

# Check for invalid port_num
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False

# 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)
reg_value = int(status)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)

# Absence of status throws error
if (reg_value == "" ):
if (reg_value == ""):
return False

# Mask off 4th bit for presence
Expand All @@ -195,33 +198,106 @@ def reset(self, port_num):
# ResetL is active low
reg_value = reg_value & ~mask

# 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)
# 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)

# Sleep 1 second to allow it to settle
time.sleep(1)

reg_value = reg_value | mask

# 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)
# 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)

return True

def get_transceiver_change_event(self):
port_dict = {}
while True:
def get_register(self, reg_file):
retval = 'ERR'
if (not path.isfile(reg_file)):
print reg_file, 'not found !'
return retval

try:
with fdopen(open(reg_file, O_RDONLY)) as fd:
retval = fd.read()
except Exception as error:
logging.error("Unable to open ", reg_file, "file !")

retval = retval.rstrip('\r\n')
retval = retval.lstrip(" ")
return retval

def check_interrupts(self, port_dict):
retval = 0
is_port_dict_updated = False
for port_num in range(self.port_start, (self.port_end + 1)):
presence = self.get_presence(port_num)
if(presence and self._global_port_pres_dict[port_num] == '0'):
is_port_dict_updated = True
self._global_port_pres_dict[port_num] = '1'
port_dict[port_num] = '1'
elif(not presence and
self._global_port_pres_dict[port_num] == '1'):
is_port_dict_updated = True
self._global_port_pres_dict[port_num] = '0'
port_dict[port_num] = '0'

if(len(port_dict) > 0):
return True, port_dict

time.sleep(0.5)
return retval, is_port_dict_updated

def get_transceiver_change_event(self, timeout=0):
port_dict = {}
try:
# We get notified when there is a MSI interrupt (vector 4/5)CVR
# Open the sysfs file and register the epoll object
self.oir_fd = fdopen(open(self.OIR_FD_PATH, O_RDONLY))
if self.oir_fd != -1:
# Do a dummy read before epoll register
self.oir_fd.read()
self.epoll = select.epoll()
self.epoll.register(
self.oir_fd.fileno(), select.EPOLLIN & select.EPOLLET)
else:
print("get_transceiver_change_event : unable to create fd")
return False, {}

# Check for missed interrupts by invoking self.check_interrupts
# which will update the port_dict.
while True:
interrupt_count_start = self.get_register(self.OIR_FD_PATH)
retval, is_port_dict_updated = \
self.check_interrupts(port_dict)
if ((retval == 0) and (is_port_dict_updated is True)):
return True, port_dict
interrupt_count_end = self.get_register(self.OIR_FD_PATH)
if (interrupt_count_start == 'ERR' or
interrupt_count_end == 'ERR'):
print("get_transceiver_change_event : \
unable to retrive interrupt count")
break

# check_interrupts() itself may take upto 100s of msecs.
# We detect a missed interrupt based on the count
if interrupt_count_start == interrupt_count_end:
break

# Block until an xcvr is inserted or removed with timeout = -1
events = self.epoll.poll(
timeout=timeout if timeout != 0 else -1)
if events:
# check interrupts and return the port_dict
retval, is_port_dict_updated = \
self.check_interrupts(port_dict)
if (retval != 0):
return False, {}

return True, port_dict
except:
return False, {}
finally:
if self.oir_fd != -1:
self.epoll.unregister(self.oir_fd.fileno())
self.epoll.close()
self.oir_fd.close()
self.oir_fd = -1
self.epoll = -1

return False, {}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ z9264f/scripts/check_qsfp.sh usr/local/bin
z9264f/scripts/platform_sensors.py usr/local/bin
z9264f/scripts/sensors usr/bin
z9264f/scripts/pcisysfs.py usr/bin
z9264f/scripts/qsfp_irq_enable.py usr/bin
z9264f/cfg/z9264f-modules.conf etc/modules-load.d
z9264f/systemd/platform-modules-z9264f.service etc/systemd/system
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0
Loading