Skip to content

Commit ae37d0a

Browse files
gengankarthikMichelMoriniaux
authored andcommitted
[devices]: DellEmc-Z9264f:Interrupt based Optic OIR (sonic-net#2926)
1 parent 8e7b35e commit ae37d0a

File tree

5 files changed

+264
-47
lines changed

5 files changed

+264
-47
lines changed

device/dell/x86_64-dellemc_z9264f_c3538-r0/plugins/sfputil.py

+121-45
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import sys
99
import getopt
1010
import time
11+
import select
1112
from sonic_sfp.sfputilbase import SfpUtilBase
1213
from os import *
1314
from mmap import *
@@ -24,6 +25,10 @@ class SfpUtil(SfpUtilBase):
2425
PORTS_IN_BLOCK = 64
2526

2627
BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0"
28+
OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi"
29+
30+
oir_fd = -1
31+
epoll = -1
2732

2833
_port_to_eeprom_mapping = {}
2934

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

4853
def pci_mem_read(self, mm, offset):
4954
mm.seek(offset)
50-
read_data_stream=mm.read(4)
51-
reg_val=struct.unpack('I',read_data_stream)
55+
read_data_stream = mm.read(4)
56+
reg_val = struct.unpack('I', read_data_stream)
5257
mem_val = str(reg_val)[1:-2]
5358
# print "reg_val read:%x"%reg_val
5459
return mem_val
5560

5661
def pci_mem_write(self, mm, offset, data):
5762
mm.seek(offset)
5863
# print "data to write:%x"%data
59-
mm.write(struct.pack('I',data))
64+
mm.write(struct.pack('I', data))
6065

6166
def pci_set_value(self, resource, val, offset):
6267
fd = open(resource, O_RDWR)
@@ -73,25 +78,23 @@ def pci_get_value(self, resource, offset):
7378
mm.close()
7479
close(fd)
7580
return val
76-
81+
7782
def init_global_port_presence(self):
7883
for port_num in range(self.port_start, (self.port_end + 1)):
7984
presence = self.get_presence(port_num)
8085
if(presence):
8186
self._global_port_pres_dict[port_num] = '1'
8287
else:
8388
self._global_port_pres_dict[port_num] = '0'
84-
89+
8590
def __init__(self):
8691
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
8792

8893
for x in range(self.port_start, self.port_end + 1):
89-
port_num = x + 1
90-
self.port_to_eeprom_mapping[x] = eeprom_path.format(
91-
port_num)
94+
port_num = x + 1
95+
self.port_to_eeprom_mapping[x] = eeprom_path.format(port_num)
9296
port_num = 0
9397
self.init_global_port_presence()
94-
9598
SfpUtilBase.__init__(self)
9699

97100
def get_presence(self, port_num):
@@ -100,13 +103,13 @@ def get_presence(self, port_num):
100103
return False
101104

102105
# Port offset starts with 0x4004
103-
port_offset = 16388 + ((port_num-1) * 16)
106+
port_offset = 16388 + ((port_num-1) * 16)
107+
108+
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
109+
reg_value = int(status)
104110

105-
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
106-
reg_value = int(status)
107-
108111
# Absence of status throws error
109-
if (reg_value == "" ):
112+
if (reg_value == ""):
110113
return False
111114

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

127-
# Port offset starts with 0x4000
128-
port_offset = 16384 + ((port_num-1) * 16)
130+
# Port offset starts with 0x4000
131+
port_offset = 16384 + ((port_num-1) * 16)
129132

130-
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
131-
reg_value = int(status)
133+
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
134+
reg_value = int(status)
132135

133136
# Absence of status throws error
134-
if (reg_value == "" ):
137+
if (reg_value == ""):
135138
return False
136139

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

152-
# Port offset starts with 0x4000
153-
port_offset = 16384 + ((port_num-1) * 16)
155+
# Port offset starts with 0x4000
156+
port_offset = 16384 + ((port_num-1) * 16)
154157

155-
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
156-
reg_value = int(status)
158+
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
159+
reg_value = int(status)
157160

158161
# Absence of status throws error
159-
if (reg_value == "" ):
162+
if (reg_value == ""):
160163
return False
161164

162165
# Mask off 4th bit for presence
163166
mask = (1 << 6)
164-
165-
# LPMode is active high; set or clear the bit accordingly
167+
168+
# LPMode is active high; set or clear the bit accordingly
166169
if lpmode is True:
167170
reg_value = reg_value | mask
168171
else:
169172
reg_value = reg_value & ~mask
170173

171174
# Convert our register value back to a hex string and write back
172-
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
175+
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
173176

174177
return True
175178

176179
def reset(self, port_num):
177180

178-
# Check for invalid port_num
181+
# Check for invalid port_num
179182
if port_num < self.port_start or port_num > self.port_end:
180183
return False
181184

182-
# Port offset starts with 0x4000
183-
port_offset = 16384 + ((port_num-1) * 16)
185+
# Port offset starts with 0x4000
186+
port_offset = 16384 + ((port_num-1) * 16)
184187

185-
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
186-
reg_value = int(status)
188+
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
189+
reg_value = int(status)
187190

188191
# Absence of status throws error
189-
if (reg_value == "" ):
192+
if (reg_value == ""):
190193
return False
191194

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

198-
# Convert our register value back to a hex string and write back
199-
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
201+
# Convert our register value back to a hex string and write back
202+
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
200203

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

204207
reg_value = reg_value | mask
205208

206-
# Convert our register value back to a hex string and write back
207-
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
209+
# Convert our register value back to a hex string and write back
210+
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
208211

209212
return True
210213

211-
def get_transceiver_change_event(self):
212-
port_dict = {}
213-
while True:
214+
def get_register(self, reg_file):
215+
retval = 'ERR'
216+
if (not path.isfile(reg_file)):
217+
print reg_file, 'not found !'
218+
return retval
219+
220+
try:
221+
with fdopen(open(reg_file, O_RDONLY)) as fd:
222+
retval = fd.read()
223+
except Exception as error:
224+
logging.error("Unable to open ", reg_file, "file !")
225+
226+
retval = retval.rstrip('\r\n')
227+
retval = retval.lstrip(" ")
228+
return retval
229+
230+
def check_interrupts(self, port_dict):
231+
retval = 0
232+
is_port_dict_updated = False
214233
for port_num in range(self.port_start, (self.port_end + 1)):
215234
presence = self.get_presence(port_num)
216235
if(presence and self._global_port_pres_dict[port_num] == '0'):
236+
is_port_dict_updated = True
217237
self._global_port_pres_dict[port_num] = '1'
218238
port_dict[port_num] = '1'
219239
elif(not presence and
220240
self._global_port_pres_dict[port_num] == '1'):
241+
is_port_dict_updated = True
221242
self._global_port_pres_dict[port_num] = '0'
222243
port_dict[port_num] = '0'
223-
224-
if(len(port_dict) > 0):
225-
return True, port_dict
226-
227-
time.sleep(0.5)
244+
return retval, is_port_dict_updated
245+
246+
def get_transceiver_change_event(self, timeout=0):
247+
port_dict = {}
248+
try:
249+
# We get notified when there is a MSI interrupt (vector 4/5)CVR
250+
# Open the sysfs file and register the epoll object
251+
self.oir_fd = fdopen(open(self.OIR_FD_PATH, O_RDONLY))
252+
if self.oir_fd != -1:
253+
# Do a dummy read before epoll register
254+
self.oir_fd.read()
255+
self.epoll = select.epoll()
256+
self.epoll.register(
257+
self.oir_fd.fileno(), select.EPOLLIN & select.EPOLLET)
258+
else:
259+
print("get_transceiver_change_event : unable to create fd")
260+
return False, {}
261+
262+
# Check for missed interrupts by invoking self.check_interrupts
263+
# which will update the port_dict.
264+
while True:
265+
interrupt_count_start = self.get_register(self.OIR_FD_PATH)
266+
retval, is_port_dict_updated = \
267+
self.check_interrupts(port_dict)
268+
if ((retval == 0) and (is_port_dict_updated is True)):
269+
return True, port_dict
270+
interrupt_count_end = self.get_register(self.OIR_FD_PATH)
271+
if (interrupt_count_start == 'ERR' or
272+
interrupt_count_end == 'ERR'):
273+
print("get_transceiver_change_event : \
274+
unable to retrive interrupt count")
275+
break
276+
277+
# check_interrupts() itself may take upto 100s of msecs.
278+
# We detect a missed interrupt based on the count
279+
if interrupt_count_start == interrupt_count_end:
280+
break
281+
282+
# Block until an xcvr is inserted or removed with timeout = -1
283+
events = self.epoll.poll(
284+
timeout=timeout if timeout != 0 else -1)
285+
if events:
286+
# check interrupts and return the port_dict
287+
retval, is_port_dict_updated = \
288+
self.check_interrupts(port_dict)
289+
if (retval != 0):
290+
return False, {}
291+
292+
return True, port_dict
293+
except:
294+
return False, {}
295+
finally:
296+
if self.oir_fd != -1:
297+
self.epoll.unregister(self.oir_fd.fileno())
298+
self.epoll.close()
299+
self.oir_fd.close()
300+
self.oir_fd = -1
301+
self.epoll = -1
302+
303+
return False, {}

platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.install

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ z9264f/scripts/check_qsfp.sh usr/local/bin
33
z9264f/scripts/platform_sensors.py usr/local/bin
44
z9264f/scripts/sensors usr/bin
55
z9264f/scripts/pcisysfs.py usr/bin
6+
z9264f/scripts/qsfp_irq_enable.py usr/bin
67
z9264f/cfg/z9264f-modules.conf etc/modules-load.d
78
z9264f/systemd/platform-modules-z9264f.service etc/systemd/system
89
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_z9264f_c3538-r0

0 commit comments

Comments
 (0)