diff --git a/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini index f04fb03264cb..77deb1931856 100644 --- a/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini +++ b/device/celestica/x86_64-cel_silverstone-r0/Silverstone-128x100/port_config.ini @@ -112,8 +112,8 @@ Ethernet218 187,188 QSFP28/2 28 100000 Ethernet220 189,190 QSFP28/3 28 100000 Ethernet222 191,192 QSFP28/4 28 100000 Ethernet224 193,194 QSFP29/1 29 100000 -Ethernet216 195,196 QSFP29/2 29 100000 -Ethernet218 197,198 QSFP29/3 29 100000 +Ethernet226 195,196 QSFP29/2 29 100000 +Ethernet228 197,198 QSFP29/3 29 100000 Ethernet230 199,200 QSFP29/4 29 100000 Ethernet232 201,202 QSFP30/1 30 100000 Ethernet234 203,204 QSFP30/2 30 100000 diff --git a/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py index fa2283831c87..d1d048a27bd6 100755 --- a/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py +++ b/device/celestica/x86_64-cel_silverstone-r0/plugins/sfputil.py @@ -4,8 +4,18 @@ # This plugin supports QSFP-DD, QSFP and SFP. try: + import syslog import time + import subprocess from sonic_platform_base.sonic_sfp.sfputilbase import SfpUtilBase + from sonic_platform_base.sonic_sfp.sff8024 import type_of_transceiver + from sonic_platform_base.sonic_sfp.sff8024 import type_of_media_interface + from sonic_platform_base.sonic_sfp.sff8024 import host_electrical_interface + from sonic_platform_base.sonic_sfp.sff8024 import nm_850_media_interface + from sonic_platform_base.sonic_sfp.sff8024 import sm_media_interface + from sonic_platform_base.sonic_sfp.sff8024 import passive_copper_media_interface + from sonic_platform_base.sonic_sfp.sff8024 import active_cable_media_interface + from sonic_platform_base.sonic_sfp.sff8024 import base_t_media_interface from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId, sff8472Dom from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId, sff8436Dom from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId @@ -15,6 +25,21 @@ raise ImportError("%s - required module not found" % str(e)) +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' +HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' +PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' + +SYSLOG_IDENTIFIER = "sfputil.py" + +def log_info(msg, also_print_to_console=False): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_INFO, msg) + syslog.closelog() + + if also_print_to_console: + print msg + class QSFPDDDomPaser(qsfp_dd_Dom): def __init__(self, eeprom_raw_data): @@ -173,7 +198,6 @@ def __init__(self, eeprom_raw_data): def get_data_pretty(self): return sffbase.get_data_pretty(self, self.dom_data) - class SfpUtil(SfpUtilBase): """Platform-specific SfpUtil class""" @@ -184,10 +208,15 @@ class SfpUtil(SfpUtilBase): SFP_PORT_START = 33 SFP_PORT_END = 34 + NUM_OSFP = 32 + EEPROM_OFFSET = 9 PORT_INFO_PATH = '/sys/class/silverstone_fpga' QSFP_DD_DOM_OFFSET = 2304 + # polling interval in seconds + POLL_INTERVAL = 1 + _port_name = "" _port_to_eeprom_mapping = {} _port_to_i2cbus_mapping = {} @@ -232,10 +261,30 @@ def get_eeprom_dom_raw(self, port_num): return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256) def __init__(self): + self.inf8628 = inf8628InterfaceId() + + self.mod_presence = {} + self.mod_failure = {} + for x in range(self.PORT_START, self.PORT_END + 1): + self.mod_failure[x] = 0 + self.mod_presence[x] = False + + self.hwsku = None + try: + proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY], + stdout=subprocess.PIPE, + shell=False, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + self.hwsku = stdout.rstrip('\n') + except: + log_info("Cannot detect HwSku") + # Override port_to_eeprom_mapping for class initialization eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' - for x in range(self.PORT_START, self.PORT_END+1): + for x in range(self.PORT_START, self.PORT_END + 1): self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET) self.port_to_eeprom_mapping[x] = eeprom_path.format( x + self.EEPROM_OFFSET) @@ -344,11 +393,152 @@ def reset(self, port_num): return True + def _page_to_flat(self, addr, page = -1): + flat = 0 + if addr < 128: + flat = addr + else: + flat = ((page + 1) << 7) | (addr & 0x7f) + return flat + + def _write_byte(self, port_num, devid, page, off, val): + eeprom_path = self._get_port_eeprom_path(port_num, devid) + addr = self._page_to_flat(off, page) + try: + f = open(eeprom_path, "wb", 0) + f.seek(addr) + f.write(chr(val)) + except Exception as ex: + log_info("write failed: {0}".format(ex)) + finally: + f.close() + + def _init_cmis_module_custom(self, port_num, xcvr, hwsku): + # As of now, init sequence is only necessary for 'INNOLIGHT T-DP4CNT-N00' + if xcvr != 'INNOLIGHT T-DP4CNT-N00': + return True + + log_info("PORT {0}: {1}: _init_cmis_module_custom".format(port_num, xcvr)) + + # Allow 1s for software reset + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, -1, 26, 0x08) + time.sleep(1) + # Deinitialize datapath + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 128, 0xff) + time.sleep(0.5) + # Hi-Power + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, -1, 26, 0x00) + # Application selection + if '128x100' in hwsku: + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 145, 0x21) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 146, 0x21) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 147, 0x25) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 148, 0x25) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 149, 0x29) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 150, 0x29) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 151, 0x2d) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 152, 0x2d) + else: + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 145, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 146, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 147, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 148, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 149, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 150, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 151, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 152, 0x11) + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 143, 0xff) + # Initialize datapath + self._write_byte(port_num, self.IDENTITY_EEPROM_ADDR, 0x10, 128, 0x00) + time.sleep(0.5) + # Validate configuration status + buf = self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, self._page_to_flat(202, 0x11), 4) + err = "".join(buf) + if err != '11111111': + log_info("PORT {0}: ConfigErr={1}".format(port_num, err)) + return False + + return True + + def _init_cmis_module(self, port_num): + buf = self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 0x80, 48) + if buf is None: + log_info("PORT {0}: unable to read PAGE0".format(port_num)) + return False + + # Skip, in case of QSFP28 + if buf[0] not in "18,19": + log_info("PORT {0}: skipped, it's not a QSFPDD".format(port_num)) + return True + + # Decode the transceiver ids + name = self.inf8628.parse_vendor_name(buf, 1)['data']['Vendor Name']['value'] + part = self.inf8628.parse_vendor_pn(buf, 20)['data']['Vendor PN']['value'] + #log_info("_init_cmis_module: p={0}, id='{1}', name='{2}', part='{3}'".format(port_num, buf[0], name, part)) + xcvr = name.upper() + " " + part.upper() + + return self._init_cmis_module_custom(port_num, xcvr, self.hwsku) + def get_transceiver_change_event(self, timeout=0): """ - TBD + :param timeout in milliseconds. The method is a blocking call. When timeout is + zero, it only returns when there is change event, i.e., transceiver plug-in/out + event. When timeout is non-zero, the function can also return when the timer expires. + When timer expires, the return status is True and events is empty. + :returns: (status, events) + :status: Boolean, True if call successful and no system level event/error occurred, + False if call not success or system level event/error occurred. + :events: dictionary for physical port index and the SFP status, + status='1' represent plug in, '0' represent plug out like {'0': '1', '31':'0'} + when it comes to system level event/error, the index will be '-1', + and status can be 'system_not_ready', 'system_become_ready', 'system_fail', + like {'-1':'system_not_ready'}. """ - raise NotImplementedError + int_sfp = {} + end_time = time.time() + (float(timeout) / 1000.0) + while end_time > time.time(): + for x in range(self.PORT_START, self.PORT_END + 1): + flag = self.get_presence(x) + if flag != self.mod_presence[x]: + int_sfp[str(x)] = '1' if flag else '0' + self.mod_failure[x] = 0 + self.mod_presence[x] = flag + + # skip the following logic in case of module absent + if not flag: + continue + + # Monitoring the QSFP-DD module state, and initiate software reset when failure count > 2 + buf = self._read_eeprom_devid(x, self.IDENTITY_EEPROM_ADDR, 0x0, 4) + if buf is None: + continue + # skip, in case of QSFP28 + if buf[0] not in "18,19": + continue + # skip, in case that CMIS < 3.0 + if int(buf[1], 16) < 0x30: + continue + # advance the failure counter if state != ModuleReady + if ((int(buf[3], 16) >> 1) & 0x7) != 3: + self.mod_failure[x] += 1 + # initiate QSFP-DD software reset if failure counter > 2 + if self.mod_failure[x] > 2: + self.mod_failure[x] = 0 + self._write_byte(x, self.IDENTITY_EEPROM_ADDR, -1, 26, 0x08) + + # Monitoring the QSFP-DD initialization state, and reinitiate it if necessary + buf = self._read_eeprom_devid(x, self.IDENTITY_EEPROM_ADDR, self._page_to_flat(202, 0x11), 4) + if buf is None: + continue + err = "".join(buf) + if err != '11111111': + if not self._init_cmis_module(x): + log_info("PORT {0}: Unable to initialize the module".format(x)) + # break if the SFP change event is not empty + if len(int_sfp) > 0: + break + time.sleep(1) + return True, int_sfp def get_qsfp_data(self, eeprom_ifraw): sfp_data = {} @@ -359,6 +549,27 @@ def get_qsfp_data(self, eeprom_ifraw): sfp_data['dom'] = sfpd_obj.get_data_pretty() if sfpd_obj else {} return sfp_data + def parse_media_type(self, eeprom_data, offset): + media_type_code = eeprom_data[offset] + dict_name = type_of_media_interface[media_type_code] + if dict_name == "nm_850_media_interface": + return nm_850_media_interface + elif dict_name == "sm_media_interface": + return sm_media_interface + elif dict_name == "passive_copper_media_interface": + return passive_copper_media_interface + elif dict_name == "active_cable_media_interface": + return active_cable_media_interface + elif dict_name == "base_t_media_interface": + return base_t_media_interface + else: + return None + + def parse_application(self, sfp_media_type_dict, host_interface, media_interface): + host_result = host_electrical_interface[host_interface] + media_result = sfp_media_type_dict[media_interface] + return host_result, media_result + def get_eeprom_dict(self, port_num): """Returns dictionary of interface and dom data. format: { : {'interface': {'version' : '1.0', 'data' : {...}}, @@ -379,9 +590,34 @@ def get_eeprom_dict(self, port_num): sfp_data['interface'] = sfpi_obj.get_data_pretty() # check if it is a 100G module - if sfp_data['interface']['data']['Identifier'] == 'QSFP28 or later': + if sfp_data['interface']['data']['Identifier'] not in [type_of_transceiver['18'], type_of_transceiver['19']]: return self.get_qsfp_data(eeprom_ifraw) + # decode application advertisement + offset = 85 + tbl = self.parse_media_type(eeprom_ifraw, offset) + ret = "" + if tbl is not None: + app = 1 + hid = int(eeprom_ifraw[1 + offset], 16) + while (app <= 8) and (hid != 0) and (hid != 0xff): + (ht, mt) = self.parse_application(tbl, eeprom_ifraw[1 + offset], eeprom_ifraw[2 + offset]) + ret += "\n {0}: {1} | {2}".format(app, ht, mt) + app += 1 + offset += 4 + hid = int(eeprom_ifraw[1 + offset], 16) + if len(ret) > 0: + sfp_data['interface']['data']['Application Advertisement'] = ret + + # decode the running application code + sel = 1 + eeprom_data = self._read_eeprom_devid(port_num, self.IDENTITY_EEPROM_ADDR, 0x880, 32) + if eeprom_data is not None: + sel = int(eeprom_data[145 - 128], 16) >> 4 + if sel < 1 or sel >= app: + sel = 1 + sfp_data['interface']['data']['Application Selected'] = "{0}".format(sel) + sfpd_obj = QSFPDDDomPaser( eeprom_ifraw + eeprom_domraw) if eeprom_domraw else None sfp_data['dom'] = sfpd_obj.get_data_pretty() if sfpd_obj else {} diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c index b7b1812be176..f09f36281b97 100644 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone/modules/switchboard.c @@ -25,7 +25,7 @@ */ #ifndef TEST_MODE -#define MOD_VERSION "1.2.1" +#define MOD_VERSION "1.3.0" #else #define MOD_VERSION "TEST" #endif @@ -193,7 +193,6 @@ PORT XCVR 0x00004000 - 0x00004FFF. */ #define INTR_INT_N 5 #define INTR_PRESENT 4 -#define INTR_TXFAULT 2 #define INTR_RXLOS 1 #define INTR_MODABS 0 @@ -208,7 +207,6 @@ PORT XCVR 0x00004000 - 0x00004FFF. */ #define MASK_INT_N 5 #define MASK_PRESENT 4 -#define MASK_TXFAULT 2 #define MASK_RXLOS 1 #define MASK_MODABS 0 @@ -555,14 +553,14 @@ static struct attribute_group fpga_attr_grp = { .attrs = fpga_attrs, }; -static ssize_t cpld1_version_show(struct device *dev, +static ssize_t cpld1_version_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 version; int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], - CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, - I2C_SMBUS_BYTE_DATA, + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], + CPLD1_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data *)&version); if (err < 0) return err; @@ -667,14 +665,14 @@ static struct attribute_group cpld1_attr_grp = { .attrs = cpld1_attrs, }; -static ssize_t cpld2_version_show(struct device *dev, +static ssize_t cpld2_version_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 version; int err; - err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], - CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, - I2C_SMBUS_BYTE_DATA, + err = fpga_i2c_access(fpga_data->i2c_adapter[SW_I2C_CPLD_INDEX], + CPLD2_SLAVE_ADDR, 0x00, I2C_SMBUS_READ, 0x00, + I2C_SMBUS_BYTE_DATA, (union i2c_smbus_data *)&version); if (err < 0) return err; @@ -929,6 +927,106 @@ static ssize_t qsfp_reset_store(struct device *dev, struct device_attribute *att } DEVICE_ATTR_RW(qsfp_reset); +static ssize_t qsfp_isr_flags_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + data = (u8) ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + /* + * Unify the return pattern to 2-bit + * [1] : module interrupt + * [0] : presence + */ + data = data & valid_bits; + data = data >> 4; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t qsfp_isr_flags_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value << 4; + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(qsfp_isr_flags); + +static ssize_t qsfp_isr_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + /* + * Unify the return pattern to 2-bit + * [1] : module interrupt + * [0] : presence + */ + data = data & valid_bits; + data = data >> 4; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t qsfp_isr_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value << 4; + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(qsfp_isr_mask); + static ssize_t sfp_txdisable_show(struct device *dev, struct device_attribute *attr, char *buf) { u32 data; @@ -967,15 +1065,105 @@ static ssize_t sfp_txdisable_store(struct device *dev, struct device_attribute * } DEVICE_ATTR_RW(sfp_txdisable); +static ssize_t sfp_isr_flags_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_RXLOS) | BIT(INTR_MODABS); + + mutex_lock(&fpga_data->fpga_lock); + data = (u8) ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + data = data & valid_bits; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t sfp_isr_flags_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_STATUS_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_INT_N) | BIT(INTR_PRESENT); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(sfp_isr_flags); + +static ssize_t sfp_isr_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 data; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_RXLOS) | BIT(INTR_MODABS); + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + + data = data & valid_bits; + + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t sfp_isr_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + ssize_t status; + u32 value; + u8 valid_bits; + struct sff_device_data *dev_data = dev_get_drvdata(dev); + unsigned int portid = dev_data->portid; + unsigned int REGISTER = SFF_PORT_INT_MASK_BASE + (portid - 1) * 0x10; + valid_bits = BIT(INTR_RXLOS) | BIT(INTR_MODABS); + + mutex_lock(&fpga_data->fpga_lock); + status = kstrtou32(buf, 0, &value); + if (status == 0) { + value = value & valid_bits; + iowrite32(value, fpga_dev.data_base_addr + REGISTER); + status = count; + } + mutex_unlock(&fpga_data->fpga_lock); + return status; +} +DEVICE_ATTR_RW(sfp_isr_mask); + static struct attribute *sff_attrs[] = { &dev_attr_qsfp_modirq.attr, &dev_attr_qsfp_modprs.attr, &dev_attr_qsfp_lpmode.attr, &dev_attr_qsfp_reset.attr, + &dev_attr_qsfp_isr_flags.attr, + &dev_attr_qsfp_isr_mask.attr, &dev_attr_sfp_txfault.attr, &dev_attr_sfp_rxlos.attr, &dev_attr_sfp_modabs.attr, &dev_attr_sfp_txdisable.attr, + &dev_attr_sfp_isr_flags.attr, + &dev_attr_sfp_isr_mask.attr, NULL, }; @@ -1036,9 +1224,9 @@ static ssize_t port_led_color_show(struct device *dev, struct device_attribute * if (err < 0) return err; return sprintf(buf, "%s %s\n", - led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : led_color1 == 0x01 ? "magenta" : "white", - led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? + led_color1 == 0x07 ? "off" : led_color1 == 0x06 ? "green" : led_color1 == 0x05 ? "red" : led_color1 == 0x04 ? "yellow" : led_color1 == 0x03 ? "blue" : led_color1 == 0x02 ? "cyan" : led_color1 == 0x01 ? "magenta" : "white"); } @@ -1137,7 +1325,7 @@ static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writin timeout = jiffies + msecs_to_jiffies(timeout); while (1) { Status = ioread8(pci_bar + REG_SR0); - if (jiffies > timeout) { + if (!time_is_after_jiffies(timeout)) { info("Status %2.2X", Status); info("Error Timeout"); error = -ETIMEDOUT; @@ -1152,6 +1340,7 @@ static int i2c_wait_ack(struct i2c_adapter *a, unsigned long timeout, int writin if (writing == 0 && (Status & (1 << I2C_SR_BIT_MCF))) { break; } + schedule(); } Status = ioread8(pci_bar + REG_SR0); iowrite8(0, pci_bar + REG_SR0); @@ -1242,7 +1431,11 @@ static int smbus_access(struct i2c_adapter *adapter, u16 addr, goto Done; } +#if 1 /* 100 kHz */ + iowrite8(portid | 0x40, pci_bar + REG_ID0); +#else iowrite8(portid, pci_bar + REG_ID0); +#endif ////[S][ADDR/R] //Clear status register @@ -1503,7 +1696,7 @@ static int fpga_i2c_access(struct i2c_adapter *adapter, u16 addr, } if(retry == 0) goto release_unlock; - // update lasted port + // update latest port fpga_i2c_lasted_access_port[master_bus - 1] = switch_addr << 8 | channel; } else { @@ -1934,7 +2127,9 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(KERN_INFO ""); fpga_version = ioread32(fpga_dev.data_base_addr); printk(KERN_INFO "FPGA VERSION : %8.8x\n", fpga_version); - fpgafw_init(); + if ((err = fpgafw_init()) < 0){ + goto pci_release; + } platform_device_register(&silverstone_dev); platform_driver_register(&silverstone_drv); return 0; @@ -1943,7 +2138,7 @@ static int fpga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) pci_release_regions(pdev); pci_disable: pci_disable_device(pdev); - return -EBUSY; + return err; } static void fpga_pci_remove(struct pci_dev *pdev) @@ -2077,7 +2272,6 @@ static int fpgafw_init(void) { static void fpgafw_exit(void) { device_destroy(fpgafwclass, MKDEV(majorNumber, 0)); // remove the device - class_unregister(fpgafwclass); // unregister the device class class_destroy(fpgafwclass); // remove the device class unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number printk(KERN_INFO "Goodbye!\n");