From a888e15e5ca7cd02d860d02cd59b943b594a0232 Mon Sep 17 00:00:00 2001 From: paavaanan Date: Tue, 4 Dec 2018 23:48:39 +0530 Subject: [PATCH] [devices]: xcvrd OIR support for Dell S6100/Z9100 switches (#2281) * xcvrd OIR support for Dell S6100/Z9100 switches Introduced check_interrupts function to handle missed interrupts. port_dict updated and returned for appropriate OIR events. Added support for both S6100/Z9100 switches. * Revamped sfputil.py for PEP8 Standards --- .../plugins/sfputil.py | 426 ++++++++++-------- .../plugins/sfputil.py | 133 ++++-- 2 files changed, 326 insertions(+), 233 deletions(-) diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py b/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py index 6521cc0e93a5..745aaae74467 100644 --- a/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dell_s6100_c2538-r0/plugins/sfputil.py @@ -95,7 +95,7 @@ class SfpUtil(SfpUtilBase): 61: [9, 31, 47, 63, 79], 62: [9, 32, 48, 64, 80], 63: [9, 33, 49, 65, 81] -} + } IOM_1_PORT_START = 0 IOM_1_PORT_END = 15 @@ -109,8 +109,11 @@ class SfpUtil(SfpUtilBase): IOM_4_PORT_START = 48 IOM_4_PORT_END = 63 - BASE_VAL_PATH="/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" + BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" + OIR_FD_PATH = "/sys/devices/platform/dell_ich.0/sci_int_gpio_sus6" + oir_fd = -1 + epoll = -1 @property def port_start(self): @@ -164,59 +167,83 @@ def port_to_eeprom_mapping(self): def port_to_i2c_mapping(self): return self._port_to_i2c_mapping - def __init__(self): eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/i2c-{1}/{1}-0050/eeprom" global port_to_eeprom_path for port_num in range(0, self.port_end + 1): - if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: - assigned=0 - #i2c-6 - for x in range(1,5): - port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) - if ( os.path.isfile(port_to_eeprom_path) ): - self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path - assigned=1 + if port_num >= self.iom1_port_start and port_num <=\ + self.iom1_port_end: + assigned = 0 + # i2c-6 + for x in range(1, 5): + port_to_eeprom_path = eeprom_path.format( + self.port_to_i2c_mapping[port_num][0], + self.port_to_i2c_mapping[port_num][x]) + if (os.path.isfile(port_to_eeprom_path)): + self.port_to_eeprom_mapping[port_num] =\ + port_to_eeprom_path + assigned = 1 elif (not assigned): - self.port_to_eeprom_mapping[port_num]="No IOM" - - elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: - assigned=0 - #i2c-8 - for x in range(1,5): - port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) - if ( os.path.isfile(port_to_eeprom_path) ): - self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path - assigned=1 + self.port_to_eeprom_mapping[port_num] =\ + "No IOM" + + elif(port_num >= self.iom2_port_start and + port_num <= self.iom2_port_end): + assigned = 0 + # i2c-8 + for x in range(1, 5): + port_to_eeprom_path = eeprom_path.format( + self.port_to_i2c_mapping[port_num][0], + self.port_to_i2c_mapping[port_num][x]) + if (os.path.isfile(port_to_eeprom_path)): + self.port_to_eeprom_mapping[port_num] =\ + port_to_eeprom_path + assigned = 1 elif (not assigned): - self.port_to_eeprom_mapping[port_num]="No IOM" - - elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: - assigned=0 - #i2c-7 - for x in range(1,5): - port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) - if ( os.path.isfile(port_to_eeprom_path) ): - self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path - assigned=1 + self.port_to_eeprom_mapping[port_num] =\ + "No IOM" + + elif(port_num >= self.iom3_port_start and port_num <= + self.iom3_port_end): + assigned = 0 + # i2c-7 + for x in range(1, 5): + port_to_eeprom_path = eeprom_path.format( + self.port_to_i2c_mapping[port_num][0], + self.port_to_i2c_mapping[port_num][x]) + if (os.path.isfile(port_to_eeprom_path)): + self.port_to_eeprom_mapping[port_num] =\ + port_to_eeprom_path + assigned = 1 elif (not assigned): - self.port_to_eeprom_mapping[port_num]="No IOM" - - - elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: - assigned=0 - #i2c-9 - for x in range(1,5): - port_to_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[port_num][0], self.port_to_i2c_mapping[port_num][x]) - if ( os.path.isfile(port_to_eeprom_path) ): - self.port_to_eeprom_mapping[port_num]=port_to_eeprom_path - assigned=1 + self.port_to_eeprom_mapping[port_num] =\ + "No IOM" + + elif(port_num >= self.iom4_port_start and port_num <= + self.iom4_port_end): + assigned = 0 + # i2c-9 + for x in range(1, 5): + port_to_eeprom_path = eeprom_path.format( + self.port_to_i2c_mapping[port_num][0], + self.port_to_i2c_mapping[port_num][x]) + if (os.path.isfile(port_to_eeprom_path)): + self.port_to_eeprom_mapping[port_num] =\ + port_to_eeprom_path + assigned = 1 elif (not assigned): - self.port_to_eeprom_mapping[port_num]="No IOM" + self.port_to_eeprom_mapping[port_num] =\ + "No IOM" SfpUtilBase.__init__(self) + def __del__(self): + if self.oir_fd != -1: + self.epoll.unregister(self.oir_fd.fileno()) + self.epoll.close() + self.oir_fd.close() + def get_presence(self, port_num): global i2c_line @@ -225,15 +252,19 @@ def get_presence(self, port_num): if port_num < self.port_start or port_num > self.port_end: return False - #port_num and i2c match - if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: - i2c_line=14 - elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: - i2c_line=16 - elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: - i2c_line=15 - elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: - i2c_line=17 + # port_num and i2c match + if(port_num >= self.iom1_port_start and port_num <= + self.iom1_port_end): + i2c_line = 14 + elif(port_num >= self.iom2_port_start and port_num <= + self.iom2_port_end): + i2c_line = 16 + elif(port_num >= self.iom3_port_start and port_num <= + self.iom3_port_end): + i2c_line = 15 + elif(port_num >= self.iom4_port_start and port_num <= + self.iom4_port_end): + i2c_line = 17 try: qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_modprs" @@ -245,16 +276,16 @@ def get_presence(self, port_num): content = reg_file.readline().rstrip() - #Absence of IOM throws read error + # Absence of IOM throws read error if (content == 'read error'): return False # content is a string containing the hex representation of the register reg_value = int(content, 16) - #Rationalize port settings + # Rationalize port settings if port_num > 15: - port_num=port_num%16 + port_num = port_num % 16 # Mask off the bit corresponding to our port mask = (1 << port_num) @@ -270,15 +301,19 @@ def get_low_power_mode(self, port_num): if port_num < self.port_start or port_num > self.port_end: return False - #port_num and i2c match - if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: - i2c_line=14 - elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: - i2c_line=16 - elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: - i2c_line=15 - elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: - i2c_line=17 + # port_num and i2c match + if(port_num >= self.iom1_port_start and port_num <= + self.iom1_port_end): + i2c_line = 14 + elif(port_num >= self.iom2_port_start and port_num <= + self.iom2_port_end): + i2c_line = 16 + elif(port_num >= self.iom3_port_start and port_num <= + self.iom3_port_end): + i2c_line = 15 + elif(port_num >= self.iom4_port_start and port_num <= + self.iom4_port_end): + i2c_line = 17 try: qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" @@ -290,16 +325,16 @@ def get_low_power_mode(self, port_num): content = reg_file.readline().rstrip() - #Absence of IOM throws read error + # Absence of IOM throws read error if (content == 'read error'): return False # content is a string containing the hex representation of the register reg_value = int(content, 16) - #Rationalize port settings + # Rationalize port settings if port_num > 15: - port_num=port_num%16 + port_num = port_num % 16 # Mask off the bit corresponding to our port mask = (1 << port_num) @@ -315,15 +350,19 @@ def set_low_power_mode(self, port_num, lpmode): if port_num < self.port_start or port_num > self.port_end: return False - #port_num and i2c match - if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: - i2c_line=14 - elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: - i2c_line=16 - elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: - i2c_line=15 - elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: - i2c_line=17 + # port_num and i2c match + if(port_num >= self.iom1_port_start and port_num <= + self.iom1_port_end): + i2c_line = 14 + elif(port_num >= self.iom2_port_start and port_num <= + self.iom2_port_end): + i2c_line = 16 + elif(port_num >= self.iom3_port_start and port_num <= + self.iom3_port_end): + i2c_line = 15 + elif(port_num >= self.iom4_port_start and port_num <= + self.iom4_port_end): + i2c_line = 17 try: qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" @@ -335,16 +374,16 @@ def set_low_power_mode(self, port_num, lpmode): content = reg_file.readline().rstrip() - #Absence of IOM throws read error + # Absence of IOM throws read error if (content == 'read error'): return False # content is a string containing the hex representation of the register reg_value = int(content, 16) - #Rationalize port settings + # Rationalize port settings if port_num > 15: - port_num=port_num%16 + port_num = port_num % 16 # Mask off the bit corresponding to our port mask = (1 << port_num) @@ -372,15 +411,19 @@ def reset(self, port_num): if port_num < self.port_start or port_num > self.port_end: return False - #port_num and i2c match - if port_num >= self.iom1_port_start and port_num <= self.iom1_port_end: - i2c_line=14 - elif port_num >= self.iom2_port_start and port_num <= self.iom2_port_end: - i2c_line=16 - elif port_num >= self.iom3_port_start and port_num <= self.iom3_port_end: - i2c_line=15 - elif port_num >= self.iom4_port_start and port_num <= self.iom4_port_end: - i2c_line=17 + # port_num and i2c match + if(port_num >= self.iom1_port_start and port_num <= + self.iom1_port_end): + i2c_line = 14 + elif(port_num >= self.iom2_port_start and port_num <= + self.iom2_port_end): + i2c_line = 16 + elif(port_num >= self.iom3_port_start and port_num <= + self.iom3_port_end): + i2c_line = 15 + elif(port_num >= self.iom4_port_start and port_num <= + self.iom4_port_end): + i2c_line = 17 try: qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" @@ -392,17 +435,18 @@ def reset(self, port_num): content = reg_file.readline().rstrip() - #Absence of IOM throws read error + # Absence of IOM throws read error if (content == 'read error'): - print("it's empty"); + print("it's empty") return False - # File content is a string containing the hex representation of the register + # File content is a string containing the hex representation + # of the register reg_value = int(content, 16) - #Rationalize port settings + # Rationalize port settings if port_num > 15: - port_num=port_num%16 + port_num = port_num % 16 # Mask off the bit corresponding to our port mask = (1 << port_num) @@ -418,7 +462,8 @@ def reset(self, port_num): # Sleep 1 second to allow it to settle time.sleep(1) - # Flip the bit back high and write back to the register to take port out of reset + # Flip the bit back high and write back to the register to take port + # out of reset try: qsfp_path = self.BASE_VAL_PATH.format(i2c_line)+"qsfp_lpmode" reg_file = open(qsfp_path, "w") @@ -434,7 +479,6 @@ def reset(self, port_num): return True - def get_register(self, reg_file): retval = 'ERR' @@ -452,101 +496,107 @@ def get_register(self, reg_file): retval = retval.lstrip(" ") return retval + def check_interrupts(self, port_dict): + retval = 0 + is_port_dict_updated = False + + # Read the QSFP ABS interrupt & status registers + cpld2_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_int") + cpld2_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_sta") + cpld3_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_int") + cpld3_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_sta") + cpld4_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_int") + cpld4_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_sta") + cpld5_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-17/17-003e/qsfp_abs_int") + cpld5_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-17/17-003e/qsfp_abs_sta") + + if (cpld2_abs_int == 'ERR' or cpld2_abs_sta == 'ERR' or + cpld3_abs_int == 'ERR' or cpld3_abs_sta == 'ERR' or + cpld4_abs_int == 'ERR' or cpld4_abs_sta == 'ERR' or + cpld5_abs_int == 'ERR' or cpld5_abs_sta == 'ERR'): + return -1 + + # If IOM is not present, interrupt will return 'read error' + # Handle the scenario gracefully + if (cpld2_abs_int == 'read error'): + cpld2_abs_int = "0x0" + cpld2_abs_sta = "0x0" + if (cpld3_abs_int == 'read error'): + cpld3_abs_int = "0x0" + cpld3_abs_sta = "0x0" + if (cpld4_abs_int == 'read error'): + cpld4_abs_int = "0x0" + cpld4_abs_sta = "0x0" + if (cpld5_abs_int == 'read error'): + cpld5_abs_int = "0x0" + cpld5_abs_sta = "0x0" + + cpld2_abs_int = int(cpld2_abs_int, 16) + cpld2_abs_sta = int(cpld2_abs_sta, 16) + cpld3_abs_int = int(cpld3_abs_int, 16) + cpld3_abs_sta = int(cpld3_abs_sta, 16) + cpld4_abs_int = int(cpld4_abs_int, 16) + cpld4_abs_sta = int(cpld4_abs_sta, 16) + cpld5_abs_int = int(cpld5_abs_int, 16) + cpld5_abs_sta = int(cpld5_abs_sta, 16) + + # Make it contiguous + interrupt_reg = (cpld2_abs_int & 0xffff) | \ + ((cpld4_abs_int & 0xffff) << 16) | \ + ((cpld3_abs_int & 0xffff) << 32) | \ + ((cpld5_abs_int & 0xffff) << 48) + status_reg = (cpld2_abs_sta & 0xffff) | \ + ((cpld4_abs_sta & 0xffff) << 16) | \ + ((cpld3_abs_sta & 0xffff) << 32) | \ + ((cpld5_abs_sta & 0xffff) << 48) + + port = self.port_start + while port <= self.port_end: + if interrupt_reg & (1 << port): + # update only if atleast one port has generated + # interrupt + is_port_dict_updated = True + if status_reg & (1 << port): + # status reg 1 => optics is removed + port_dict[port] = '0' + else: + # status reg 0 => optics is inserted + port_dict[port] = '1' + port += 1 + return retval, is_port_dict_updated + def get_transceiver_change_event(self, timeout=0): - epoll = select.epoll() port_dict = {} try: - # We get notified when there is an SCI interrupt from GPIO SUS6 - fd = open("/sys/devices/platform/dell_ich.0/sci_int_gpio_sus6", "r") - epoll.register(fd.fileno(), select.EPOLLIN) - events = epoll.poll(timeout=timeout if timeout != 0 else -1) - if events: - # Read the QSFP ABS interrupt & status registers - cpld2_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_int") - cpld2_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_sta") - cpld3_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_int") - cpld3_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_sta") - cpld4_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_int") - cpld4_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_sta") - cpld5_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-17/17-003e/qsfp_abs_int") - cpld5_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-17/17-003e/qsfp_abs_sta") - - - if (cpld2_abs_int == 'read error' or cpld2_abs_sta == 'read error' or \ - cpld3_abs_int == 'read error' or cpld3_abs_sta == 'read error' or \ - cpld4_abs_int == 'read error' or cpld4_abs_sta == 'read error' or \ - cpld4_abs_int == 'read error' or cpld4_abs_sta == 'read error' ): - return False, {} - - cpld2_abs_int = int(cpld2_abs_int, 16) - cpld2_abs_sta = int(cpld2_abs_sta, 16) - cpld3_abs_int = int(cpld3_abs_int, 16) - cpld3_abs_sta = int(cpld3_abs_sta, 16) - cpld4_abs_int = int(cpld4_abs_int, 16) - cpld4_abs_sta = int(cpld4_abs_sta, 16) - cpld5_abs_int = int(cpld5_abs_int, 16) - cpld5_abs_sta = int(cpld5_abs_sta, 16) - - port=self.port_start - - while port >= self.iom1_port_start and port <= self.iom1_port_end: - - interrupt_reg = cpld2_abs_int - status_reg = cpld2_abs_sta - - if interrupt_reg & (1< optics is removed - port_dict[port] = '0' - else: - # status reg 0 => optics is inserted - port_dict[port] = '1' - port += 1 - - while port >= self.iom2_port_start and port <= self.iom2_port_end: - - interrupt_reg = cpld4_abs_int - status_reg = cpld4_abs_sta - - if interrupt_reg & (1< optics is removed - port_dict[port] = '0' - else: - # status reg 0 => optics is inserted - port_dict[port] = '1' - port += 1 - - while port >= self.iom3_port_start and port <= self.iom3_port_end: - - interrupt_reg = cpld3_abs_int - status_reg = cpld3_abs_sta - - if interrupt_reg & (1< optics is removed - port_dict[port] = '0' - else: - # status reg 0 => optics is inserted - port_dict[port] = '1' - port += 1 - - while port >= self.iom4_port_start and port <= self.iom4_port_end: - - interrupt_reg = cpld5_abs_int - status_reg = cpld5_sta - - if interrupt_reg & (1< optics is removed - port_dict[port] = '0' - else: - # status reg 0 => optics is inserted - port_dict[port] = '1' - port += 1 - return True, port_dict - finally: - fd.close() - epoll.close() + # We get notified when there is an SCI interrupt from GPIO SUS6 + # Check for missed interrupts by invoking self.check_interrupts + # it will update the port_dict. + # Then poll for new xcvr insertion/removal and + # call self.check_interrupts again and return + retval, is_port_dict_updated = self.check_interrupts(port_dict) + if ((retval == 0) and (is_port_dict_updated is True)): + return True, port_dict + + # 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, {} return False, {} + diff --git a/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py b/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py index 11be23b7e2d7..b31a44ca1539 100644 --- a/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py +++ b/device/dell/x86_64-dell_z9100_c2538-r0/plugins/sfputil.py @@ -27,7 +27,10 @@ class SfpUtil(SfpUtilBase): IOM_3_PORT_END = 31 BASE_VAL_PATH = "/sys/class/i2c-adapter/i2c-{0}/{0}-003e/" + OIR_FD_PATH = "/sys/devices/platform/dell_ich.0/sci_int_gpio_sus6" + oir_fd = -1 + epoll = -1 _port_to_eeprom_mapping = {} _port_to_i2c_mapping = { 0: [9, 18], @@ -116,8 +119,19 @@ def __init__(self): self.port_to_i2c_mapping[x][0], self.port_to_i2c_mapping[x][1]) + self.oir_fd = open(self.OIR_FD_PATH, "r") + self.epoll = select.epoll() + if self.oir_fd != -1: + self.epoll.register(self.oir_fd.fileno(), select.EPOLLIN) + SfpUtilBase.__init__(self) + def __del__(self): + if self.oir_fd != -1: + self.epoll.unregister(self.oir_fd.fileno()) + self.epoll.close() + self.oir_fd.close() + def get_presence(self, port_num): global i2c_line @@ -358,52 +372,81 @@ def get_register(self, reg_file): retval = retval.lstrip(" ") return retval + def check_interrupts(self, port_dict): + retval = 0 + is_port_dict_updated = False + # Read the QSFP ABS interrupt & status registers + cpld2_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_int") + cpld2_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_sta") + cpld3_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_int") + cpld3_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_sta") + cpld4_abs_int = self.get_register( + "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_int") + cpld4_abs_sta = self.get_register( + "/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_sta") + + if (cpld2_abs_int == 'ERR' or cpld2_abs_sta == 'ERR' or + cpld3_abs_int == 'ERR' or cpld3_abs_sta == 'ERR' or + cpld4_abs_int == 'ERR' or cpld4_abs_sta == 'ERR'): + return -1 + + cpld2_abs_int = int(cpld2_abs_int, 16) + cpld2_abs_sta = int(cpld2_abs_sta, 16) + cpld3_abs_int = int(cpld3_abs_int, 16) + cpld3_abs_sta = int(cpld3_abs_sta, 16) + cpld4_abs_int = int(cpld4_abs_int, 16) + cpld4_abs_sta = int(cpld4_abs_sta, 16) + + # Make it contiguous (discard reserved bits) + interrupt_reg = (cpld2_abs_int & 0xfff) |\ + ((cpld3_abs_int & 0x3ff) << 12) |\ + ((cpld4_abs_int & 0x3ff) << 22) + status_reg = (cpld2_abs_sta & 0xfff) |\ + ((cpld3_abs_sta & 0x3ff) << 12) |\ + ((cpld4_abs_sta & 0x3ff) << 22) + + port = self.port_start + while port <= self.port_end: + if interrupt_reg & (1 << port): + # update only if atleast one port has generated + # interrupt + is_port_dict_updated = True + if status_reg & (1 << port): + # status reg 1 => optics is removed + port_dict[port] = '0' + else: + # status reg 0 => optics is inserted + port_dict[port] = '1' + port += 1 + return retval, is_port_dict_updated + def get_transceiver_change_event(self, timeout=0): - epoll = select.epoll() port_dict = {} try: - # We get notified when there is an SCI interrupt from GPIO SUS6 - fd = open("/sys/devices/platform/dell_ich.0/sci_int_gpio_sus6", "r") - epoll.register(fd.fileno(), select.EPOLLIN) - events = epoll.poll(timeout=timeout if timeout != 0 else -1) - if events: - # Read the QSFP ABS interrupt & status registers - cpld2_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_int") - cpld2_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-14/14-003e/qsfp_abs_sta") - cpld3_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_int") - cpld3_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-15/15-003e/qsfp_abs_sta") - cpld4_abs_int = self.get_register("/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_int") - cpld4_abs_sta = self.get_register("/sys/class/i2c-adapter/i2c-16/16-003e/qsfp_abs_sta") - - if (cpld2_abs_int == 'ERR' or cpld2_abs_sta == 'ERR' or \ - cpld3_abs_int == 'ERR' or cpld3_abs_sta == 'ERR' or \ - cpld4_abs_int == 'ERR' or cpld4_abs_sta == 'ERR' ): - return False, {} - - cpld2_abs_int = int(cpld2_abs_int, 16) - cpld2_abs_sta = int(cpld2_abs_sta, 16) - cpld3_abs_int = int(cpld3_abs_int, 16) - cpld3_abs_sta = int(cpld3_abs_sta, 16) - cpld4_abs_int = int(cpld4_abs_int, 16) - cpld4_abs_sta = int(cpld4_abs_sta, 16) - - # Make it contiguous (discard reserved bits) - interrupt_reg = (cpld2_abs_int & 0xfff) | ((cpld3_abs_int & 0x3ff) << 12) | ((cpld4_abs_int & 0x3ff) << 22) - status_reg = (cpld2_abs_sta & 0xfff) | ((cpld3_abs_sta & 0x3ff) << 12) | ((cpld4_abs_sta & 0x3ff) << 22) - - port=self.port_start - while port <= self.port_end: - if interrupt_reg & (1< optics is removed - port_dict[port] = '0' - else: - # status reg 0 => optics is inserted - port_dict[port] = '1' - port += 1 - return True, port_dict - finally: - fd.close() - epoll.close() - + # We get notified when there is an SCI interrupt from GPIO SUS6 + # Check for missed interrupts by invoking self.check_interrupts + # it will update the port_dict. + # Then poll for new xcvr insertion/removal and + # call self.check_interrupts again and return + retval, is_port_dict_updated = self.check_interrupts(port_dict) + if ((retval == 0) and (is_port_dict_updated is True)): + return True, port_dict + + # 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, {} return False, {} +