8
8
import sys
9
9
import getopt
10
10
import time
11
+ import select
11
12
from sonic_sfp .sfputilbase import SfpUtilBase
12
13
from os import *
13
14
from mmap import *
@@ -24,6 +25,10 @@ class SfpUtil(SfpUtilBase):
24
25
PORTS_IN_BLOCK = 64
25
26
26
27
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
27
32
28
33
_port_to_eeprom_mapping = {}
29
34
@@ -47,16 +52,16 @@ def port_to_eeprom_mapping(self):
47
52
48
53
def pci_mem_read (self , mm , offset ):
49
54
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 )
52
57
mem_val = str (reg_val )[1 :- 2 ]
53
58
# print "reg_val read:%x"%reg_val
54
59
return mem_val
55
60
56
61
def pci_mem_write (self , mm , offset , data ):
57
62
mm .seek (offset )
58
63
# print "data to write:%x"%data
59
- mm .write (struct .pack ('I' ,data ))
64
+ mm .write (struct .pack ('I' , data ))
60
65
61
66
def pci_set_value (self , resource , val , offset ):
62
67
fd = open (resource , O_RDWR )
@@ -73,25 +78,23 @@ def pci_get_value(self, resource, offset):
73
78
mm .close ()
74
79
close (fd )
75
80
return val
76
-
81
+
77
82
def init_global_port_presence (self ):
78
83
for port_num in range (self .port_start , (self .port_end + 1 )):
79
84
presence = self .get_presence (port_num )
80
85
if (presence ):
81
86
self ._global_port_pres_dict [port_num ] = '1'
82
87
else :
83
88
self ._global_port_pres_dict [port_num ] = '0'
84
-
89
+
85
90
def __init__ (self ):
86
91
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
87
92
88
93
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 )
92
96
port_num = 0
93
97
self .init_global_port_presence ()
94
-
95
98
SfpUtilBase .__init__ (self )
96
99
97
100
def get_presence (self , port_num ):
@@ -100,13 +103,13 @@ def get_presence(self, port_num):
100
103
return False
101
104
102
105
# 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 )
104
110
105
- status = self .pci_get_value (self .BASE_RES_PATH , port_offset )
106
- reg_value = int (status )
107
-
108
111
# Absence of status throws error
109
- if (reg_value == "" ):
112
+ if (reg_value == "" ):
110
113
return False
111
114
112
115
# Mask off 4th bit for presence
@@ -124,14 +127,14 @@ def get_low_power_mode(self, port_num):
124
127
if port_num < self .port_start or port_num > self .port_end :
125
128
return False
126
129
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 )
129
132
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 )
132
135
133
136
# Absence of status throws error
134
- if (reg_value == "" ):
137
+ if (reg_value == "" ):
135
138
return False
136
139
137
140
# Mask off 4th bit for presence
@@ -149,44 +152,44 @@ def set_low_power_mode(self, port_num, lpmode):
149
152
if port_num < self .port_start or port_num > self .port_end :
150
153
return False
151
154
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 )
154
157
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 )
157
160
158
161
# Absence of status throws error
159
- if (reg_value == "" ):
162
+ if (reg_value == "" ):
160
163
return False
161
164
162
165
# Mask off 4th bit for presence
163
166
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
166
169
if lpmode is True :
167
170
reg_value = reg_value | mask
168
171
else :
169
172
reg_value = reg_value & ~ mask
170
173
171
174
# 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 )
173
176
174
177
return True
175
178
176
179
def reset (self , port_num ):
177
180
178
- # Check for invalid port_num
181
+ # Check for invalid port_num
179
182
if port_num < self .port_start or port_num > self .port_end :
180
183
return False
181
184
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 )
184
187
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 )
187
190
188
191
# Absence of status throws error
189
- if (reg_value == "" ):
192
+ if (reg_value == "" ):
190
193
return False
191
194
192
195
# Mask off 4th bit for presence
@@ -195,33 +198,106 @@ def reset(self, port_num):
195
198
# ResetL is active low
196
199
reg_value = reg_value & ~ mask
197
200
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 )
200
203
201
204
# Sleep 1 second to allow it to settle
202
205
time .sleep (1 )
203
206
204
207
reg_value = reg_value | mask
205
208
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 )
208
211
209
212
return True
210
213
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
214
233
for port_num in range (self .port_start , (self .port_end + 1 )):
215
234
presence = self .get_presence (port_num )
216
235
if (presence and self ._global_port_pres_dict [port_num ] == '0' ):
236
+ is_port_dict_updated = True
217
237
self ._global_port_pres_dict [port_num ] = '1'
218
238
port_dict [port_num ] = '1'
219
239
elif (not presence and
220
240
self ._global_port_pres_dict [port_num ] == '1' ):
241
+ is_port_dict_updated = True
221
242
self ._global_port_pres_dict [port_num ] = '0'
222
243
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 , {}
0 commit comments