#include #include #include #include #include "io_expander.h" #include "transceiver.h" /* ========== Register EEPROM address mapping ========== */ struct eeprom_map_s eeprom_map_sfp = { .addr_br =0x50, .page_br =-1, .offset_br =12, .length_br =1, .addr_cdr =-1, .page_cdr =-1, .offset_cdr =-1, .length_cdr =-1, .addr_comp_rev =0x50, .page_comp_rev =-1, .offset_comp_rev =94, .length_comp_rev =1, .addr_connector =0x50, .page_connector =-1, .offset_connector =2, .length_connector =1, .addr_diag_type =0x50, .page_diag_type =-1, .offset_diag_type =92 , .length_diag_type =1, .addr_extbr =-1, .page_extbr =-1, .offset_extbr =-1, .length_extbr =-1, .addr_ext_id =0x50, .page_ext_id =-1, .offset_ext_id =1, .length_ext_id =1, .addr_id =0x50, .page_id =-1, .offset_id =0, .length_id =1, .addr_len_sm =0x50, .page_len_sm =-1, .offset_len_sm =15, .length_len_sm =1, .addr_len_smf =0x50, .page_len_smf =-1, .offset_len_smf =14, .length_len_smf =1, .addr_len_om1 =0x50, .page_len_om1 =-1, .offset_len_om1 =17, .length_len_om1 =1, .addr_len_om2 =0x50, .page_len_om2 =-1, .offset_len_om2 =16, .length_len_om2 =1, .addr_len_om3 =0x50, .page_len_om3 =-1, .offset_len_om3 =19, .length_len_om3 =1, .addr_len_om4 =0x50, .page_len_om4 =-1, .offset_len_om4 =18, .length_len_om4 =1, .addr_option =0x50, .page_option =-1, .offset_option =64, .length_option =2, .addr_rate_id =0x50, .page_rate_id =-1, .offset_rate_id =13, .length_rate_id =1, .addr_rx_am =-1, .page_rx_am =-1, .offset_rx_am =-1, .length_rx_am =-1, .addr_rx_em =0x51, .page_rx_em =-1, .offset_rx_em =115, .length_rx_em =1, .addr_rx_los =-1, .page_rx_los =-1, .offset_rx_los =-1, .length_rx_los =-1, .addr_rx_power =0x51, .page_rx_power =-1, .offset_rx_power =104, .length_rx_power =2, .addr_soft_rs0 =0x51, .page_soft_rs0 =-1, .offset_soft_rs0 =110, .length_soft_rs0 =1, .addr_soft_rs1 =0x51, .page_soft_rs1 =-1, .offset_soft_rs1 =118, .length_soft_rs0 =1, .addr_temp =0x51, .page_temp =-1, .offset_temp =96, .length_temp =2, .addr_trancomp =0x50, .page_trancomp =-1, .offset_trancomp =3, .length_trancomp =8, .addr_trancomp_ext =0x50, .page_trancomp_ext =-1, .offset_trancomp_ext =36, .length_trancomp_ext =1, .addr_tx_bias =0x51, .page_tx_bias =-1, .offset_tx_bias =100, .length_tx_bias =2, .addr_tx_disable =-1, .page_tx_disable =-1, .offset_tx_disable =-1, .length_tx_disable =-1, .addr_tx_eq =0x51, .page_tx_eq =-1, .offset_tx_eq =114, .length_tx_eq =1, .addr_tx_fault =-1, .page_tx_fault =-1, .offset_tx_fault =-1, .length_tx_fault =-1, .addr_tx_power =0x51, .page_tx_power =-1, .offset_tx_power =102, .length_tx_power =2, .addr_vendor_name =0x50, .page_vendor_name =-1, .offset_vendor_name =20, .length_vendor_name =16, .addr_vendor_pn =0x50, .page_vendor_pn =-1, .offset_vendor_pn =40, .length_vendor_pn =16, .addr_vendor_rev =0x50, .page_vendor_rev =-1, .offset_vendor_rev =56, .length_vendor_rev =4, .addr_vendor_sn =0x50, .page_vendor_sn =-1, .offset_vendor_sn =68, .length_vendor_sn =16, .addr_voltage =0x51, .page_voltage =-1, .offset_voltage =98, .length_voltage =2, .addr_wavelength =0x50, .page_wavelength =-1, .offset_wavelength =60, .length_wavelength =2, }; struct eeprom_map_s eeprom_map_qsfp = { .addr_br =0x50, .page_br =0, .offset_br =140, .length_br =1, .addr_cdr =-1, .page_cdr =-1, .offset_cdr =-1, .length_cdr =-1, .addr_comp_rev =0x50, .page_comp_rev =-1, .offset_comp_rev =1, .length_comp_rev =1, .addr_connector =0x50, .page_connector =0, .offset_connector =130, .length_connector =1, .addr_diag_type =0x50, .page_diag_type =0, .offset_diag_type =220, .length_diag_type =1, .addr_extbr =0x50, .page_extbr =0, .offset_extbr =222, .length_extbr =1, .addr_ext_id =0x50, .page_ext_id =0, .offset_ext_id =129, .length_ext_id =1, .addr_id =0x50, .page_id =0, .offset_id =128, .length_id =1, .addr_len_sm =-1, .page_len_sm =-1, .offset_len_sm =-1, .length_len_sm =-1, .addr_len_smf =0x50, .page_len_smf =0, .offset_len_smf =142, .length_len_smf =1, .addr_len_om1 =0x50, .page_len_om1 =0, .offset_len_om1 =145, .length_len_om1 =1, .addr_len_om2 =0x50, .page_len_om2 =0, .offset_len_om2 =144, .length_len_om2 =1, .addr_len_om3 =0x50, .page_len_om3 =0, .offset_len_om3 =143, .length_len_om3 =1, .addr_len_om4 =0x50, .page_len_om4 =0, .offset_len_om4 =146, .length_len_om4 =1, .addr_option =0x50, .page_option =0, .offset_option =193, .length_option =3, .addr_rate_id =-1, .page_rate_id =-1, .offset_rate_id =-1, .length_rate_id =-1, .addr_rx_am =-1, .page_rx_am =-1, .offset_rx_am =-1, .length_rx_am =-1, .addr_rx_em =-1, .page_rx_em =-1, .offset_rx_em =-1, .length_rx_em =-1, .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1, .addr_rx_power =0x50, .page_rx_power =-1, .offset_rx_power =34, .length_rx_power =8, .addr_soft_rs0 =-1, .page_soft_rs0 =-1, .offset_soft_rs0 =-1, .length_soft_rs0 =-1, .addr_soft_rs1 =-1, .page_soft_rs1 =-1, .offset_soft_rs1 =-1, .length_soft_rs0 =-1, .addr_temp =0x50, .page_temp =-1, .offset_temp =22, .length_temp =2, .addr_trancomp =0x50, .page_trancomp =0, .offset_trancomp =131, .length_trancomp =8, .addr_trancomp_ext =0x50, .page_trancomp_ext =0, .offset_trancomp_ext =192, .length_trancomp_ext =1, .addr_tx_bias =0x50, .page_tx_bias =-1, .offset_tx_bias =42, .length_tx_bias =8, .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1, .addr_tx_eq =-1, .page_tx_eq =-1, .offset_tx_eq =-1, .length_tx_eq =-1, .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1, .addr_tx_power =0x50, .page_tx_power =-1, .offset_tx_power =50, .length_tx_power =8, .addr_vendor_name =0x50, .page_vendor_name =0, .offset_vendor_name =148, .length_vendor_name =16, .addr_vendor_pn =0x50, .page_vendor_pn =0, .offset_vendor_pn =168, .length_vendor_pn =16, .addr_vendor_rev =0x50, .page_vendor_rev =0, .offset_vendor_rev =184, .length_vendor_rev =2, .addr_vendor_sn =0x50, .page_vendor_sn =0, .offset_vendor_sn =196, .length_vendor_sn =16, .addr_voltage =0x50, .page_voltage =-1, .offset_voltage =26, .length_voltage =2, .addr_wavelength =0x50, .page_wavelength =0, .offset_wavelength =186, .length_wavelength =2, }; struct eeprom_map_s eeprom_map_qsfp28 = { .addr_br =0x50, .page_br =0, .offset_br =140, .length_br =1, .addr_cdr =0x50, .page_cdr =-1, .offset_cdr =98, .length_cdr =1, .addr_comp_rev =0x50, .page_comp_rev =-1, .offset_comp_rev =1, .length_comp_rev =1, .addr_connector =0x50, .page_connector =0, .offset_connector =130, .length_connector =1, .addr_diag_type =0x50, .page_diag_type =0, .offset_diag_type =220, .length_diag_type =1, .addr_extbr =0x50, .page_extbr =0, .offset_extbr =222, .length_extbr =1, .addr_ext_id =0x50, .page_ext_id =0, .offset_ext_id =129, .length_ext_id =1, .addr_id =0x50, .page_id =0, .offset_id =128, .length_id =1, .addr_len_sm =-1, .page_len_sm =-1, .offset_len_sm =-1, .length_len_sm =-1, .addr_len_smf =0x50, .page_len_smf =0, .offset_len_smf =142, .length_len_smf =1, .addr_len_om1 =0x50, .page_len_om1 =0, .offset_len_om1 =145, .length_len_om1 =1, .addr_len_om2 =0x50, .page_len_om2 =0, .offset_len_om2 =144, .length_len_om2 =1, .addr_len_om3 =0x50, .page_len_om3 =0, .offset_len_om3 =143, .length_len_om3 =1, .addr_len_om4 =0x50, .page_len_om4 =0, .offset_len_om4 =146, .length_len_om4 =1, .addr_option =0x50, .page_option =0, .offset_option =193, .length_option =3, .addr_rate_id =-1, .page_rate_id =-1, .offset_rate_id =-1, .length_rate_id =-1, .addr_rx_am =0x50, .page_rx_am =3, .offset_rx_am =238, .length_rx_am =2, .addr_rx_em =0x50, .page_rx_em =3, .offset_rx_em =236, .length_rx_em =2, .addr_rx_los =0x50, .page_rx_los =-1, .offset_rx_los =3, .length_rx_los =1, .addr_rx_power =0x50, .page_rx_power =-1, .offset_rx_power =34, .length_rx_power =8, .addr_soft_rs0 =-1, .page_soft_rs0 =-1, .offset_soft_rs0 =-1, .length_soft_rs0 =-1, .addr_soft_rs1 =-1, .page_soft_rs1 =-1, .offset_soft_rs1 =-1, .length_soft_rs0 =-1, .addr_temp =0x50, .page_temp =-1, .offset_temp =22, .length_temp =2, .addr_trancomp =0x50, .page_trancomp =0, .offset_trancomp =131, .length_trancomp =8, .addr_trancomp_ext =0x50, .page_trancomp_ext =0, .offset_trancomp_ext =192, .length_trancomp_ext =1, .addr_tx_bias =0x50, .page_tx_bias =-1, .offset_tx_bias =42, .length_tx_bias =8, .addr_tx_disable =0x50, .page_tx_disable =-1, .offset_tx_disable =86, .length_tx_disable =1, .addr_tx_eq =0x50, .page_tx_eq =3, .offset_tx_eq =234, .length_tx_eq =2, .addr_tx_fault =0x50, .page_tx_fault =-1, .offset_tx_fault =4, .length_tx_fault =1, .addr_tx_power =0x50, .page_tx_power =-1, .offset_tx_power =50, .length_tx_power =8, .addr_vendor_name =0x50, .page_vendor_name =0, .offset_vendor_name =148, .length_vendor_name =16, .addr_vendor_pn =0x50, .page_vendor_pn =0, .offset_vendor_pn =168, .length_vendor_pn =16, .addr_vendor_rev =0x50, .page_vendor_rev =0, .offset_vendor_rev =184, .length_vendor_rev =2, .addr_vendor_sn =0x50, .page_vendor_sn =0, .offset_vendor_sn =196, .length_vendor_sn =16, .addr_voltage =0x50, .page_voltage =-1, .offset_voltage =26, .length_voltage =2, .addr_wavelength =0x50, .page_wavelength =0, .offset_wavelength =186, .length_wavelength =2, }; /* ========== Utility Functions ========== */ static int get_bit(uint8_t origin_byte, int bit_shift) { return (int)((origin_byte >> bit_shift) & 0x1); } static int transform_word_to_int(uint8_t hight_byte, uint8_t low_byte) { return ((((int)hight_byte) << 8) + (int)low_byte); } void alarm_msg_2_user(struct transvr_obj_s *self, char *emsg) { SWPS_ERR("%s on %s.\n", emsg, self->swp_name); } /* ========== Private functions ========== */ static int _reload_transvr_obj(struct transvr_obj_s *self,int new_type); static int reload_transvr_obj(struct transvr_obj_s *self,int new_type); static int _is_transvr_support_ctle(struct transvr_obj_s *self); static int _transvr_init_handler(struct transvr_obj_s *self); int _transvr_clean_handler(struct transvr_obj_s *self); int _sfp_detect_class_by_1g_ethernet(struct transvr_obj_s* self); void lock_transvr_obj(struct transvr_obj_s *self) { mutex_lock(&self->lock); self->curr_page = VAL_TRANSVR_PAGE_FREE; } void unlock_transvr_obj(struct transvr_obj_s *self) { self->curr_page = VAL_TRANSVR_PAGE_FREE; mutex_unlock(&self->lock); } static int _check_by_mode(struct transvr_obj_s *self, int (*attr_update_func)(struct transvr_obj_s *self, int show_err), char *caller_name){ int return_val = ERR_TRANSVR_UNEXCPT; switch (self->mode){ case TRANSVR_MODE_POLLING: switch (self->state){ case STATE_TRANSVR_CONNECTED: goto ok_check_by_mode_1; case STATE_TRANSVR_NEW: case STATE_TRANSVR_INIT: return ERR_TRANSVR_UNINIT; case STATE_TRANSVR_DISCONNECTED: return ERR_TRANSVR_UNPLUGGED; case STATE_TRANSVR_UNEXCEPTED: return ERR_TRANSVR_ABNORMAL; case STATE_TRANSVR_ISOLATED: return ERR_TRNASVR_BE_ISOLATED; default: goto err_check_by_mode_1; } goto ok_check_by_mode_1; case TRANSVR_MODE_DIRECT: return_val = self->fsm_4_direct(self, caller_name); if (return_val < 0){ return return_val; } goto ok_check_by_mode_1; default: goto err_check_by_mode_1; } goto ok_check_by_mode_1; ok_check_by_mode_1: return attr_update_func(self, 0); err_check_by_mode_1: SWPS_INFO("_check_by_mode: mode:%d state:%d\n", self->mode, self->state); return ERR_TRANSVR_UNEXCPT; } static void _transvr_clean_retry(struct transvr_obj_s *self) { self->retry = 0; } static int _transvr_handle_retry(struct transvr_obj_s *self, int retry) { /* Return: 0: keep retry * -1: stop retry */ if (self->retry == 0) { self->retry = retry; } self->retry -= 1; if (self->retry <= 0) { _transvr_clean_retry(self); return -1; } return 0; } static int _common_setup_page(struct transvr_obj_s *self, int addr, int page, int offset, int len, int show_e) { /* return: * 0 : OK * -1 : EEPROM settings incorrect * -2 : I2C R/W failure * -3 : Undefined case */ int retval = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; /* Check */ if ((addr < 0) || (offset < 0) || (len < 0)) { emsg = "EEPROM settings incorrect"; retval = -1; goto err_common_setup_page; } /* Case1: continue access */ if ((self->i2c_client_p->addr == addr) && (self->curr_page == page)) { return 0; } self->i2c_client_p->addr = addr; /* Case2: select lower page */ if (page == -1) { self->curr_page = page; return 0; } /* Case3: select upper page */ if (page >= 0) { goto upper_common_setup_page; } /* Unexpected case */ show_e = 1; emsg = "Unexpected case"; retval = -3; goto err_common_setup_page; upper_common_setup_page: if (i2c_smbus_write_byte_data(self->i2c_client_p, VAL_TRANSVR_PAGE_SELECT_OFFSET, page) < 0) { emsg = "I2C R/W failure"; retval = -2; goto err_common_setup_page; } self->curr_page = page; mdelay(VAL_TRANSVR_PAGE_SELECT_DELAY); return 0; err_common_setup_page: if (show_e) { SWPS_INFO("%s: %s", __func__, emsg); SWPS_INFO("%s: :0x%02x :%d :%d :%d\n", __func__, addr, page, offset, len); } return retval; } /* static int _common_setup_password(struct transvr_obj_s *self, int addr, int page, int offs, uint8_t pwd[4], int show_e) { int i = 0; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; err = _common_setup_page(self, addr, page, offs, 4, show_e); if (err < 0){ emsg = "setup EEPROM page fail"; goto err_common_setup_password; } for (i=0; i<4; i++) { err = i2c_smbus_write_byte_data(self->i2c_client_p, (offs + i), pwd[i]); if (err < 0){ emsg = "I2C R/W fail!"; goto err_common_setup_password; } } return 0; err_common_setup_password: if (show_e) { SWPS_INFO("%s: %s :%d\n", __func__, emsg, err); } return ERR_TRANSVR_UPDATE_FAIL; } */ static int _common_update_uint8_attr(struct transvr_obj_s *self, int addr, int page, int offset, int len, uint8_t *buf, char *caller, int show_e){ int i; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; err = _common_setup_page(self, addr, page, offset, len, show_e); if (err < 0){ emsg = "setup EEPROM page fail"; goto err_common_update_uint8_attr; } for (i=0; ii2c_client_p, (offset + i)); if (err < 0){ emsg = "I2C R/W fail!"; goto err_common_update_uint8_attr; } buf[i] = err; } return 0; err_common_update_uint8_attr: if (show_e) { SWPS_INFO("%s: %s :%s :%d\n", __func__, emsg, caller, err); } buf[0] = DEBUG_TRANSVR_HEX_VAL; return ERR_TRANSVR_UPDATE_FAIL; } static int _common_update_int_attr(struct transvr_obj_s *self, int addr, int page, int offset, int len, int *buf, char *caller, int show_e){ int i; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; err = _common_setup_page(self, addr, page, offset, len, show_e); if (err < 0){ emsg = "setup EEPROM page fail"; goto err_common_update_int_attr; } for (i=0; ii2c_client_p, (offset + i)); if (err < 0){ emsg = "I2C R/W fail!"; goto err_common_update_int_attr; } buf[i] = (int)err; } return 0; err_common_update_int_attr: if (show_e) { SWPS_INFO("%s: %s :%s :%d\n", __func__, emsg, caller, err); } buf[0] = DEBUG_TRANSVR_INT_VAL; return ERR_TRANSVR_UPDATE_FAIL; } static int _common_update_string_attr(struct transvr_obj_s *self, int addr, int page, int offset, int len, char buf[], char *caller, int show_e){ int i; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; err = _common_setup_page(self, addr, page, offset, len, show_e); if (err < 0){ emsg = "setup EEPROM page fail"; goto err_common_update_string_attr; } for (i=0; ii2c_client_p, (offset + i)); if (err < 0){ emsg = "I2C R/W fail!"; goto err_common_update_string_attr; } buf[i] = (char)err; } return 0; err_common_update_string_attr: if (show_e) { SWPS_INFO("%s: %s :%s :%d\n", __func__, emsg, caller, err); } buf[0] = 'e'; return ERR_TRANSVR_UPDATE_FAIL; } static int _common_set_uint8_attr(struct transvr_obj_s *self, int addr, int page, int offset, uint8_t update, uint8_t *buf, char *caller, int show_e){ int len = 1; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; if ((*buf) == update){ return 0; } err = _common_setup_page(self, addr, page, offset, len, show_e); if (err < 0){ emsg = "setup EEPROM page fail"; goto err_common_set_uint8_attr_1; } err = i2c_smbus_write_byte_data(self->i2c_client_p, offset, update); if (err < 0){ emsg = "I2C R/W fail!"; goto err_common_set_uint8_attr_1; } (*buf) = update; return 0; err_common_set_uint8_attr_1: if (show_e) { SWPS_INFO("%s: %s :%s :%d\n", __func__, emsg, caller, err); } return ERR_TRANSVR_UPDATE_FAIL; } static int _common_set_uint8_array(struct transvr_obj_s *self, int addr, int page, int offs, int len, uint8_t update[], uint8_t buf[], char *caller, int show_e){ int i = 0; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; err = _common_setup_page(self, addr, page, offs, len, show_e); if (err < 0){ emsg = "setup EEPROM page fail"; goto err_common_set_uint8_attr_1; } for (i=0; ii2c_client_p, (offs + i), update[i]); if (err < 0){ emsg = "I2C R/W fail!"; goto err_common_set_uint8_attr_1; } buf[i] = update[i]; } return 0; err_common_set_uint8_attr_1: if (show_e) { SWPS_INFO("%s: %s :%s :%d :%d\n", __func__, emsg, caller, err, i); } return ERR_TRANSVR_UPDATE_FAIL; } static int _common_update_attr_id(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_id, self->eeprom_map_p->page_id, self->eeprom_map_p->offset_id, self->eeprom_map_p->length_id, &(self->id), "_common_update_attr_id", show_err); } static int _common_update_attr_extended_id(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_ext_id, self->eeprom_map_p->page_ext_id, self->eeprom_map_p->offset_ext_id, self->eeprom_map_p->length_ext_id, &(self->ext_id), "_common_update_attr_extended_id", show_err); } static int _common_update_attr_connector(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_connector, self->eeprom_map_p->page_connector, self->eeprom_map_p->offset_connector, self->eeprom_map_p->length_connector, &(self->connector), "_common_update_attr_connector", show_err); } static int _common_update_attr_transvr_comp(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_trancomp, self->eeprom_map_p->page_trancomp, self->eeprom_map_p->offset_trancomp, self->eeprom_map_p->length_trancomp, self->transvr_comp, "_common_update_attr_transvr_comp", show_err); } static int _common_update_attr_transvr_comp_ext(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_trancomp_ext, self->eeprom_map_p->page_trancomp_ext, self->eeprom_map_p->offset_trancomp_ext, self->eeprom_map_p->length_trancomp_ext, &(self->transvr_comp_ext), "_common_update_attr_transvr_comp_ext", show_err); } static int _common_update_attr_vendor_name(struct transvr_obj_s *self, int show_err){ return _common_update_string_attr(self, self->eeprom_map_p->addr_vendor_name, self->eeprom_map_p->page_vendor_name, self->eeprom_map_p->offset_vendor_name, self->eeprom_map_p->length_vendor_name, self->vendor_name, "_common_update_attr_vendor_name", show_err); } static int _common_update_attr_vendor_pn(struct transvr_obj_s *self, int show_err){ return _common_update_string_attr(self, self->eeprom_map_p->addr_vendor_pn, self->eeprom_map_p->page_vendor_pn, self->eeprom_map_p->offset_vendor_pn, self->eeprom_map_p->length_vendor_pn, self->vendor_pn, "_common_update_attr_vendor_pn", show_err); } static int _common_update_attr_vendor_rev(struct transvr_obj_s *self, int show_err){ return _common_update_string_attr(self, self->eeprom_map_p->addr_vendor_rev, self->eeprom_map_p->page_vendor_rev, self->eeprom_map_p->offset_vendor_rev, self->eeprom_map_p->length_vendor_rev, self->vendor_rev, "_common_update_attr_vendor_rev", show_err); } static int _common_update_attr_vendor_sn(struct transvr_obj_s *self, int show_err){ return _common_update_string_attr(self, self->eeprom_map_p->addr_vendor_sn, self->eeprom_map_p->page_vendor_sn, self->eeprom_map_p->offset_vendor_sn, self->eeprom_map_p->length_vendor_sn, self->vendor_sn, "_common_update_attr_vendor_sn", show_err); } static int _common_update_attr_br(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_br, self->eeprom_map_p->page_br, self->eeprom_map_p->offset_br, self->eeprom_map_p->length_br, &(self->br), "_common_update_attr_br", show_err); } static int _common_update_attr_len_smf(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_len_smf, self->eeprom_map_p->page_len_smf, self->eeprom_map_p->offset_len_smf, self->eeprom_map_p->length_len_smf, &(self->len_smf), "_common_update_attr_len_smf", show_err); } static int _common_update_attr_len_om1(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_len_om1, self->eeprom_map_p->page_len_om1, self->eeprom_map_p->offset_len_om1, self->eeprom_map_p->length_len_om1, &(self->len_om1), "_common_update_attr_len_om1", show_err); } static int _common_update_attr_len_om2(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_len_om2, self->eeprom_map_p->page_len_om2, self->eeprom_map_p->offset_len_om2, self->eeprom_map_p->length_len_om2, &(self->len_om2), "_common_update_attr_len_om2", show_err); } static int _common_update_attr_len_om3(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_len_om3, self->eeprom_map_p->page_len_om3, self->eeprom_map_p->offset_len_om3, self->eeprom_map_p->length_len_om3, &(self->len_om3), "_common_update_attr_len_om3", show_err); } static int _common_update_attr_len_om4(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_len_om4, self->eeprom_map_p->page_len_om4, self->eeprom_map_p->offset_len_om4, self->eeprom_map_p->length_len_om4, &(self->len_om4), "_common_update_attr_len_om4", show_err); } static int _common_update_attr_option(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_option, self->eeprom_map_p->page_option, self->eeprom_map_p->offset_option, self->eeprom_map_p->length_option, self->option, "_common_update_attr_option", show_err); } static int _common_update_attr_comp_rev(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_comp_rev, self->eeprom_map_p->page_comp_rev, self->eeprom_map_p->offset_comp_rev, self->eeprom_map_p->length_comp_rev, &(self->comp_rev), "_common_update_attr_comp_rev", show_err); } static int _common_update_attr_diag_type(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_diag_type, self->eeprom_map_p->page_diag_type, self->eeprom_map_p->offset_diag_type, self->eeprom_map_p->length_diag_type, &(self->diag_type), "_common_update_attr_diag_type", show_err); } static int _common_update_attr_wavelength(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_wavelength, self->eeprom_map_p->page_wavelength, self->eeprom_map_p->offset_wavelength, self->eeprom_map_p->length_wavelength, self->wavelength, "_common_update_attr_wavelength", show_err); } int _common_get_option_value(struct transvr_obj_s *self, int offset, int bit_shift) { /* SFP: * - option[0] = A0h / 64 * - option[1] = A0h / 65 * QSFP: * - option[0] = 00h / 193 * - option[1] = 00h / 194 * - option[2] = 00h / 195 */ return (self->option[offset] & (1 << bit_shift)); } static int _sfp_update_attr_len_sm(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_len_sm, self->eeprom_map_p->page_len_sm, self->eeprom_map_p->offset_len_sm, self->eeprom_map_p->length_len_sm, &(self->len_sm), "_common_update_attr_len_sm", show_err); } static int _sfp_update_attr_rate_id(struct transvr_obj_s *self, int show_err){ return _common_update_int_attr(self, self->eeprom_map_p->addr_rate_id, self->eeprom_map_p->page_rate_id, self->eeprom_map_p->offset_rate_id, self->eeprom_map_p->length_rate_id, &(self->rate_id), "_sfp_update_attr_rate_id", show_err); } static int _sfp_update_attr_soft_rs0(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_soft_rs0, self->eeprom_map_p->page_soft_rs0, self->eeprom_map_p->offset_soft_rs0, self->eeprom_map_p->length_soft_rs0, &(self->soft_rs0), "_sfp_update_attr_soft_rs0", show_err); } static int _sfp_update_attr_soft_rs1(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_soft_rs1, self->eeprom_map_p->page_soft_rs1, self->eeprom_map_p->offset_soft_rs1, self->eeprom_map_p->length_soft_rs1, &(self->soft_rs1), "_sfp_update_attr_soft_rs1", show_err); } int _sfp_is_diag_support(struct transvr_obj_s *self){ uint8_t bit_mask = 0xC0; /* 1100 0000 */ uint8_t en_val = 0x40; /* 0100 0000 */ uint8_t checkval = (self->diag_type & bit_mask); if (checkval == en_val) { return 1; } return 0; } static int _sfp_update_attr_curr_temp(struct transvr_obj_s *self, int show_err){ if (!(_sfp_is_diag_support(self))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_temp, self->eeprom_map_p->page_temp, self->eeprom_map_p->offset_temp, self->eeprom_map_p->length_temp, self->curr_temp, "_sfp_update_attr_curr_temp", show_err); } static int _sfp_update_attr_curr_voltage(struct transvr_obj_s *self, int show_err){ if (!(_sfp_is_diag_support(self))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_voltage, self->eeprom_map_p->page_voltage, self->eeprom_map_p->offset_voltage, self->eeprom_map_p->length_voltage, self->curr_voltage, "_sfp_update_attr_curr_voltage", show_err); } static int _sfp_update_attr_curr_tx_bias(struct transvr_obj_s *self, int show_err){ if (!(_sfp_is_diag_support(self))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_bias, self->eeprom_map_p->page_tx_bias, self->eeprom_map_p->offset_tx_bias, self->eeprom_map_p->length_tx_bias, self->curr_tx_bias, "_sfp_update_attr_curr_tx_bias", show_err); } static int _sfp_update_attr_curr_tx_power(struct transvr_obj_s *self, int show_err){ if (!(_sfp_is_diag_support(self))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_power, self->eeprom_map_p->page_tx_power, self->eeprom_map_p->offset_tx_power, self->eeprom_map_p->length_tx_power, self->curr_tx_power, "_sfp_update_attr_curr_tx_power", show_err); } static int _sfp_update_attr_curr_rx_power(struct transvr_obj_s *self, int show_err){ if (!(_sfp_is_diag_support(self))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_rx_power, self->eeprom_map_p->page_rx_power, self->eeprom_map_p->offset_rx_power, self->eeprom_map_p->length_rx_power, self->curr_rx_power, "_sfp_update_attr_curr_rx_power", show_err); } static int _sfp_update_attr_rx_em(struct transvr_obj_s *self, int show_err){ if (!_is_transvr_support_ctle(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_rx_em, self->eeprom_map_p->page_rx_em, self->eeprom_map_p->offset_rx_em, self->eeprom_map_p->length_rx_em, self->rx_em, "_sfp_update_attr_rx_em", show_err); } static int _sfp_update_attr_tx_eq(struct transvr_obj_s *self, int show_err){ if (!_is_transvr_support_ctle(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_eq, self->eeprom_map_p->page_tx_eq, self->eeprom_map_p->offset_tx_eq, self->eeprom_map_p->length_tx_eq, self->tx_eq, "_sfp_update_attr_tx_eq", show_err); } static int _qsfp_update_attr_cdr(struct transvr_obj_s *self, int show_err){ if (self->type != TRANSVR_TYPE_QSFP_28){ self->cdr = DEBUG_TRANSVR_HEX_VAL; return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_cdr, self->eeprom_map_p->page_cdr, self->eeprom_map_p->offset_cdr, self->eeprom_map_p->length_cdr, &(self->cdr), "_common_update_attr_cdr", show_err); } static int _qsfg_update_attr_extbr(struct transvr_obj_s *self, int show_err) { return _common_update_uint8_attr(self, self->eeprom_map_p->addr_extbr, self->eeprom_map_p->page_extbr, self->eeprom_map_p->offset_extbr, self->eeprom_map_p->length_extbr, &(self->extbr), "_common_update_attr_extbr", show_err); } static int _qsfp_is_diag_support(struct transvr_obj_s *self, int diag_type) { /* Input Parm: diag_type * => 1 : temperature * => 2 : voltage * => 3 : tx relate * => 4 : rx relate */ uint8_t mask_b2 = 0x04; /* 0000 0100 */ uint8_t mask_b3 = 0x08; /* 0000 1000 */ switch (diag_type) { case 1: /* temperature */ case 2: /* voltage */ /* Direct access target, because of spec not defined */ return 1; case 3: case 4: /* [Note] * Due to lot of transceiver vendor defined it not rigorously and * consider of general support, we seem it as supported if there * are bit-2 OR bit-3 defined by transceiver vendor. */ if ( ((self->diag_type & mask_b2) == mask_b2 ) || ((self->diag_type & mask_b3) == mask_b3 ) ){ return 1; } return 0; default: SWPS_INFO("%s: undefined diag_type:%d\n", __func__, diag_type); break; } return 0; } int _qsfp_is_implement_tx_disable(struct transvr_obj_s *self) { /* * 00h / Byte-195 / Bit-4 */ int byte = 2; int bit = 4; return _common_get_option_value(self, byte, bit); } int _qsfp_is_implement_tx_fault(struct transvr_obj_s *self) { /* * 00h / Byte-195 / Bit-3 */ int byte = 2; int bit = 3; return _common_get_option_value(self, byte, bit); } static int _qsfp_update_attr_curr_temp(struct transvr_obj_s *self, int show_err){ int diag_type = 1; if (!(_qsfp_is_diag_support(self, diag_type))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_temp, self->eeprom_map_p->page_temp, self->eeprom_map_p->offset_temp, self->eeprom_map_p->length_temp, self->curr_temp, "_qsfp_update_attr_curr_temp", show_err); } static int _qsfp_update_attr_curr_voltage(struct transvr_obj_s *self, int show_err){ int diag_type = 2; if (!(_qsfp_is_diag_support(self, diag_type))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_voltage, self->eeprom_map_p->page_voltage, self->eeprom_map_p->offset_voltage, self->eeprom_map_p->length_voltage, self->curr_voltage, "_qsfp_update_attr_curr_voltage", show_err); } static int _qsfp_update_attr_curr_tx_bias(struct transvr_obj_s *self, int show_err){ int diag_type = 3; if (!(_qsfp_is_diag_support(self, diag_type))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_bias, self->eeprom_map_p->page_tx_bias, self->eeprom_map_p->offset_tx_bias, self->eeprom_map_p->length_tx_bias, self->curr_tx_bias, "_qsfp_update_attr_curr_tx_bias", show_err); } static int _qsfp_update_attr_curr_tx_power(struct transvr_obj_s *self, int show_err){ int diag_type = 3; if (!(_qsfp_is_diag_support(self, diag_type))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_power, self->eeprom_map_p->page_tx_power, self->eeprom_map_p->offset_tx_power, self->eeprom_map_p->length_tx_power, self->curr_tx_power, "_qsfp_update_attr_curr_tx_power", show_err); } static int _qsfp_update_attr_curr_rx_power(struct transvr_obj_s *self, int show_err){ int diag_type = 4; if (!(_qsfp_is_diag_support(self, diag_type))) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_rx_power, self->eeprom_map_p->page_rx_power, self->eeprom_map_p->offset_rx_power, self->eeprom_map_p->length_rx_power, self->curr_rx_power, "_qsfp_update_attr_curr_rx_power", show_err); } static int _qsfp_update_attr_soft_rx_los(struct transvr_obj_s *self, int show_err){ return _common_update_uint8_attr(self, self->eeprom_map_p->addr_rx_los, self->eeprom_map_p->page_rx_los, self->eeprom_map_p->offset_rx_los, self->eeprom_map_p->length_rx_los, &(self->rx_los), "_qsfp_update_attr_soft_rx_los", show_err); } static int _qsfp_update_attr_soft_tx_disable(struct transvr_obj_s *self, int show_err){ if (!_qsfp_is_implement_tx_disable(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_disable, self->eeprom_map_p->page_tx_disable, self->eeprom_map_p->offset_tx_disable, self->eeprom_map_p->length_tx_disable, &(self->tx_disable), "_qsfp_update_attr_soft_tx_disable", show_err); } static int _qsfp_update_attr_soft_tx_fault(struct transvr_obj_s *self, int show_err){ if (!_qsfp_is_implement_tx_fault(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_fault, self->eeprom_map_p->page_tx_fault, self->eeprom_map_p->offset_tx_fault, self->eeprom_map_p->length_tx_fault, &(self->tx_fault), "_qsfp_update_attr_soft_tx_fault", show_err); } static int _qsfp_update_attr_tx_eq(struct transvr_obj_s *self, int show_err){ if (!_is_transvr_support_ctle(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_eq, self->eeprom_map_p->page_tx_eq, self->eeprom_map_p->offset_tx_eq, self->eeprom_map_p->length_tx_eq, self->tx_eq, "_qsfp_update_attr_tx_eq", show_err); } static int _qsfp_update_attr_rx_am(struct transvr_obj_s *self, int show_err){ if (!_is_transvr_support_ctle(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_rx_am, self->eeprom_map_p->page_rx_am, self->eeprom_map_p->offset_rx_am, self->eeprom_map_p->length_rx_am, self->rx_am, "_qsfp_update_attr_rx_am", show_err); } static int _qsfp_update_attr_rx_em(struct transvr_obj_s *self, int show_err){ if (!_is_transvr_support_ctle(self)) { return ERR_TRANSVR_NOTSUPPORT; } return _common_update_uint8_attr(self, self->eeprom_map_p->addr_rx_em, self->eeprom_map_p->page_rx_em, self->eeprom_map_p->offset_rx_em, self->eeprom_map_p->length_rx_em, self->rx_em, "_qsfp_update_attr_rx_em", show_err); } int _common_update_attr_all(struct transvr_obj_s *self, int show_err){ char *err_str = "err"; if (_common_update_attr_id(self, show_err) < 0) { err_str = "_common_update_attr_id"; goto err_common_update_attr_all; } if (_common_update_attr_extended_id(self, show_err) < 0) { err_str = "_common_update_attr_extended_id"; goto err_common_update_attr_all; } if (_common_update_attr_connector(self, show_err) < 0) { err_str = "_common_update_attr_connector"; goto err_common_update_attr_all; } if (_common_update_attr_transvr_comp(self, show_err) < 0) { err_str = "_common_update_attr_transvr_comp"; goto err_common_update_attr_all; } if (_common_update_attr_transvr_comp_ext(self, show_err) < 0) { err_str = "_common_update_attr_transvr_comp_ext"; goto err_common_update_attr_all; } if (_common_update_attr_vendor_name(self, show_err) < 0) { err_str = "_common_update_attr_vendor_name"; goto err_common_update_attr_all; } if (_common_update_attr_vendor_pn(self, show_err) < 0) { err_str = "_common_update_attr_vendor_pn"; goto err_common_update_attr_all; } if (_common_update_attr_vendor_rev(self, show_err) < 0) { err_str = "_common_update_attr_vendor_rev"; goto err_common_update_attr_all; } if (_common_update_attr_vendor_sn(self, show_err) < 0) { err_str = "_common_update_attr_vendor_sn"; goto err_common_update_attr_all; } if (_common_update_attr_br(self, show_err) < 0) { err_str = "_common_update_attr_br"; goto err_common_update_attr_all; } if (_common_update_attr_len_smf(self, show_err) < 0) { err_str = "_common_update_attr_len_smf"; goto err_common_update_attr_all; } if (_common_update_attr_len_om1(self, show_err) < 0) { err_str = "_common_update_attr_len_om1"; goto err_common_update_attr_all; } if (_common_update_attr_len_om2(self, show_err) < 0) { err_str = "_common_update_attr_len_om2"; goto err_common_update_attr_all; } if (_common_update_attr_len_om3(self, show_err) < 0) { err_str = "_common_update_attr_len_om3"; goto err_common_update_attr_all; } if (_common_update_attr_len_om4(self, show_err) < 0) { err_str = "_common_update_attr_len_om4"; goto err_common_update_attr_all; } if (_common_update_attr_option(self, show_err) < 0) { err_str = "_common_update_attr_option"; goto err_common_update_attr_all; } if (_common_update_attr_comp_rev(self, show_err) < 0) { err_str = "_common_update_attr_comp_rev"; goto err_common_update_attr_all; } if (_common_update_attr_diag_type(self, show_err) < 0) { err_str = "_common_update_attr_diag_type"; goto err_common_update_attr_all; } if (_common_update_attr_wavelength(self, show_err) < 0) { err_str = "_common_update_attr_wavelength"; goto err_common_update_attr_all; } return 0; err_common_update_attr_all: if (show_err){ SWPS_INFO("%s: fail at:%s :%s\n", __func__, err_str, self->swp_name); } return -1; } int _sfp_update_attr_all(struct transvr_obj_s *self, int show_err){ char *err_str = DEBUG_TRANSVR_STR_VAL; if (_common_update_attr_all(self, show_err) < 0){ err_str = "_common_update_attr_all"; goto err_sfp_update_attr_all; } if (_sfp_update_attr_len_sm(self, show_err) < 0) { err_str = "_sfp_update_attr_len_sm"; goto err_sfp_update_attr_all; } if (_sfp_update_attr_rate_id(self, show_err) < 0) { err_str = "_sfp_update_attr_rate_id"; goto err_sfp_update_attr_all; } if ((self->rate_id) > 0) { if (_sfp_update_attr_soft_rs0(self, show_err) < 0) { err_str = "_sfp_update_attr_soft_rs0"; goto err_sfp_update_attr_all; } if (_sfp_update_attr_soft_rs1(self, show_err) < 0) { err_str = "_sfp_update_attr_soft_rs1"; goto err_sfp_update_attr_all; } } return 0; err_sfp_update_attr_all: if (show_err){ SWPS_INFO("%s: fail at:%s :%s\n", __func__, err_str, self->swp_name); } return -1; } int _qsfp_update_attr_all(struct transvr_obj_s *self, int show_err){ char *err_str = DEBUG_TRANSVR_STR_VAL; if (_common_update_attr_all(self, show_err) < 0){ err_str = "_common_update_attr_all"; goto err_qsfp_update_attr_all; } if (_qsfg_update_attr_extbr(self, show_err) < 0) { err_str = "_qsfg_update_attr_extbr"; goto err_qsfp_update_attr_all; } if (self->type == TRANSVR_TYPE_QSFP_28) { if (_qsfp_update_attr_cdr(self, 1) < 0) { err_str = "_qsfp_update_attr_cdr"; goto err_qsfp_update_attr_all; } } return 0; err_qsfp_update_attr_all: if (show_err){ SWPS_INFO("%s: fail at:%s :%s\n", __func__, err_str, self->swp_name); } return -1; } /* ========== Object functions for common type ========== */ int _common_count_temp(uint8_t high_byte, uint8_t low_byte, char *buf_p) { int sign = 0; int high = 0; int low = 0; int lmax = 8; /* Count high */ sign = get_bit(high_byte,7); SWP_BIT_CLEAR(high_byte, 7); high = (int)high_byte; if (sign == 1) { high = 0 - high; } /* Count low */ low = (get_bit(low_byte, 7) * 500); low += (get_bit(low_byte, 6) * 250); low += (get_bit(low_byte, 5) * 125); low += (get_bit(low_byte, 4) * 62); low = (low / 100); /* Integrate High and Low */ return snprintf(buf_p, lmax, "%d.%d\n", high, low); } int _common_count_voltage(uint8_t high_byte, uint8_t low_byte, char *buf_p) { /* [Note]: * Internally measured transceiver supply voltage. Represented * as a 16 bit unsigned integer with the voltage defined as the * full 16 bit value (0-65535) with LSB equal to 100 uVolt, * yielding a total range of 0 to +6.55 Volts. Practical * considerations to be defined by transceiver manufacturer will * tend to limit the actual bounds of the supply voltage measurement. * Accuracy is vendor specific but must be better than 3% of the * manufacturer's nominal value over specified operating temperature * and voltage. Note that in some transceivers, transmitter supply * voltage and receiver supply voltage are isolated. In that case, * only one supply is monitored. Refer to the device specification * for more detail. */ int total = 0; int lmax = 8; int val_i = 0; int val_f = 0; /* unit: 100 uV (1mV=1000uV) */ total = transform_word_to_int(high_byte, low_byte); val_i = ((total/10) / 1000); val_f = ((total/10) - (val_i*1000)); /* Return Unit: 1 Volt */ return snprintf(buf_p, lmax, "%d.%03d\n", val_i, val_f); } int _common_count_tx_bias(uint8_t high_byte, uint8_t low_byte, char *buf_p) { /* [Note] * Measured TX bias current in uA. Represented as a 16 bit unsigned * integer with the current defined as the full 16 bit value (0-65535) * with LSB equal to 2 uA, yielding a total range of 0 to 131 mA. * Accuracy is vendor specific but must be better than 10% of the * manufacturer's nominal value over specified operating temperature * and voltage. */ int total = 0; int lmax = 8; int val_i = 0; int val_f = 0; /* unit: 2 uA (1mA=1000uA) */ total = transform_word_to_int(high_byte, low_byte); val_i = ((total*2) / 1000); val_f = (((total*2) - (val_i*1000)) / 100); /* Return Unit: 1 mA */ return snprintf(buf_p, lmax, "%d.%01d\n", val_i, val_f); } int _common_count_tx_power(uint8_t high_byte, uint8_t low_byte, char *buf_p) { /* [Note] * Measured TX output power in mW. Represented as a 16 bit unsigned * integer with the power defined as the full 16 bit value (0-65535) * with LSB equal to 0.1 uW, yielding a total range of 0 to 6.5535 mW * (~ -40 to +8.2 dBm). Data is assumed to be based on measurement of * laser monitor photodiode current. It is factory calibrated to absolute * units using the most representative fiber output type. Accuracy is * vendor specific but must be better than 3dB over specified temperature * and voltage. Data is not valid when the transmitter is disabled. */ int total = 0; int lmax = 8; int val_i = 0; int val_f = 0; /* unit: 0.1 uW (1mW=1000uW) */ total = transform_word_to_int(high_byte, low_byte); val_i = ((total/10) / 1000); val_f = ((total/10) - (val_i*1000)); /* Return Unit: 1 mW */ return snprintf(buf_p, lmax, "%d.%03d\n", val_i, val_f); } int _common_count_rx_power(uint8_t high_byte, uint8_t low_byte, char *buf_p) { /* [Note] * Measured RX received optical power in mW. Value can represent either * average received power or OMA depending upon how bit 3 of byte 92 (A0h) * is set. Represented as a 16 bit unsigned integer with the power defined * as the full 16 bit value (0-65535) with LSB equal to 0.1 uW, yielding a * total range of 0 to 6.5535 mW (~ -40 to +8.2 dBm). Absolute accuracy is * dependent upon the exact optical wavelength. For the vendor specified * wavelength, accuracy shall be better than 3dB over specified temperature * and voltage. */ int total = 0; int lmax = 8; int val_i = 0; int val_f = 0; /* unit: 0.1 uW (1mW=1000uW) */ total = transform_word_to_int(high_byte, low_byte); val_i = ((total/10) / 1000); val_f = ((total/10) - (val_i*1000)); /* Return Unit: 1 mW */ return snprintf(buf_p, lmax, "%d.%03d\n", val_i, val_f); } int _common_count_wavelength(struct transvr_obj_s *self, uint8_t high_byte, uint8_t low_byte) { /* [Note] * SFP : uint 1 um. * QSFP: unit 0.05 um. */ int total = 0; total = transform_word_to_int(high_byte, low_byte); switch (self->type) { case TRANSVR_TYPE_SFP: return total; case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: case TRANSVR_TYPE_QSFP_28: return (total/20); default: break; } return ERR_TRANSVR_UNDEFINED; } int common_get_id(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_id, "common_get_id"); if (err_code < 0){ return err_code; } /* Transform to INT to show error case */ return (int)self->id; } int common_get_ext_id(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_extended_id, "common_get_ext_id"); if (err_code < 0){ return err_code; } /* Transform to INT to show error case */ return (int)self->ext_id; } int common_get_connector(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_connector, "common_get_connector"); if (err_code < 0){ return err_code; } /* Transform to INT to show error case */ return (int)self->connector; } int common_get_vendor_name(struct transvr_obj_s *self, char *buf){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_name); } err = _check_by_mode(self, &_common_update_attr_vendor_name, "common_get_vendor_name"); memset(buf, 0, LEN_TRANSVR_M_STR); if (err < 0){ return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err); } return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_name); } int common_get_vendor_pn(struct transvr_obj_s *self, char *buf) { int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_pn); } err = _check_by_mode(self, &_common_update_attr_vendor_pn, "common_get_vendor_pn"); memset(buf, 0, LEN_TRANSVR_M_STR); if (err < 0){ return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err); } return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_pn); } int common_get_vendor_rev(struct transvr_obj_s *self, char *buf) { int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_rev); } err = _check_by_mode(self, &_common_update_attr_vendor_rev, "common_get_vendor_rev"); memset(buf, 0, LEN_TRANSVR_M_STR); if (err < 0){ return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err); } return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_rev); } int common_get_vendor_sn(struct transvr_obj_s *self, char *buf) { int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_sn); } err = _check_by_mode(self, &_common_update_attr_vendor_sn, "common_get_vendor_sn"); memset(buf, 0, LEN_TRANSVR_M_STR); if (err < 0){ return snprintf(buf, LEN_TRANSVR_M_STR, "%d\n", err); } return snprintf(buf, LEN_TRANSVR_M_STR, "%s\n", self->vendor_sn); } int common_get_br(struct transvr_obj_s *self){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return (int)self->br; } err = _check_by_mode(self, &_common_update_attr_br, "common_get_br"); if (err < 0){ return err; } /* Transform to INT to show error case */ return (int)self->br; } int common_get_len_smf(struct transvr_obj_s *self){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return self->len_smf; } err = _check_by_mode(self, &_common_update_attr_len_smf, "common_get_len_smf"); if (err < 0){ return err; } return self->len_smf; } int common_get_len_om1(struct transvr_obj_s *self){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return self->len_om1; } err = _check_by_mode(self, &_common_update_attr_len_om1, "common_get_len_om1"); if (err < 0){ return err; } return self->len_om1; } int common_get_len_om2(struct transvr_obj_s *self){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return self->len_om2; } err = _check_by_mode(self, &_common_update_attr_len_om2, "common_get_len_om2"); if (err < 0){ return err; } return self->len_om2; } int common_get_len_om3(struct transvr_obj_s *self){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return self->len_om3; } err = _check_by_mode(self, &_common_update_attr_len_om3, "common_get_len_om3"); if (err < 0){ return err; } return self->len_om3; } int common_get_len_om4(struct transvr_obj_s *self){ int err = DEBUG_TRANSVR_INT_VAL; if (self->state == STATE_TRANSVR_CONNECTED && self->mode == TRANSVR_MODE_POLLING && TRANSVR_INFO_CACHE_ENABLE) { return self->len_om4; } err = _check_by_mode(self, &_common_update_attr_len_om4, "common_get_len_om4"); if (err < 0){ return err; } return self->len_om4; } int common_get_comp_extended(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_transvr_comp_ext, "common_get_comp_extended"); if (err_code < 0){ return err_code; } return self->transvr_comp_ext; } int common_get_comp_rev(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_comp_rev, "common_get_comp_rev"); if (err_code < 0){ return err_code; } return self->comp_rev; } int common_get_info(struct transvr_obj_s *self){ if (self->state != STATE_TRANSVR_CONNECTED) { return self->state; } return self->info; } int _common_get_if_lane(struct transvr_obj_s *self, char *result){ int i = 0; int tmp_val = 0; char tmp_str[LEN_TRANSVR_M_STR] = DEBUG_TRANSVR_STR_VAL; memset(result, 0, LEN_TRANSVR_M_STR); for (i=0; ilane_id); i++) { tmp_val = self->lane_id[i]; if (tmp_val < 1) { break; } memset(tmp_str, 0, LEN_TRANSVR_M_STR); if (i == 0) { snprintf(tmp_str, LEN_TRANSVR_M_STR, "%d", tmp_val); } else { snprintf(tmp_str, LEN_TRANSVR_M_STR, ",%d", tmp_val); } strncat(result, tmp_str, LEN_TRANSVR_M_STR); } if (i == 0) { return EVENT_TRANSVR_TASK_FAIL; } return 0; } int common_get_if_lane(struct transvr_obj_s *self, char *buf_p){ char tmp_str[LEN_TRANSVR_M_STR] = DEBUG_TRANSVR_STR_VAL; if (self->ioexp_obj_p->state != STATE_IOEXP_NORMAL) { return snprintf(buf_p, LEN_TRANSVR_M_STR, "%d\n", ERR_TRANSVR_ABNORMAL); } if (_common_get_if_lane(self, tmp_str) < 0) { return snprintf(buf_p, LEN_TRANSVR_M_STR, "%d\n" ,ERR_TRANSVR_ABNORMAL); } return snprintf(buf_p, LEN_TRANSVR_M_STR, "%s\n" ,tmp_str); } int sfp_get_len_sm(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_sfp_update_attr_len_sm, "sfp_get_len_sm"); if (err_code < 0){ return err_code; } return self->len_sm; } int sfp_get_rate_id(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_sfp_update_attr_rate_id, "sfp_get_rate_id"); if (err_code < 0){ return err_code; } return self->rate_id; } int sfp_get_soft_rs0(struct transvr_obj_s *self){ /* Note: * SFP Soft Rate_Select Select [aka. "RS(0)"] address * A2h, offset: 110, bit 3 (begin form 0) */ int err_code = DEBUG_TRANSVR_INT_VAL; int bit_shift = 3; uint8_t result = 0x00; uint8_t bitmask = (1 << bit_shift); /* Check rate identifier is supported */ err_code = self->get_rate_id(self); if (err_code <= 0) { return ERR_TRANSVR_NOTSUPPORT; } /* Update and check */ err_code = _check_by_mode(self, &_sfp_update_attr_soft_rs0, "sfp_get_soft_rs0"); if (err_code <0){ return err_code; } result = (self->soft_rs0 & bitmask); if (result == bitmask) { return 1; } if (result == 0) { return 0; } return ERR_TRANSVR_UNEXCPT; } int sfp_get_soft_rs1(struct transvr_obj_s *self){ /* Note: * SFP Soft RS(1) Select address * A2h, offset: 118, bit 3 (begin form 0) */ int err_code = DEBUG_TRANSVR_INT_VAL; int bit_shift = 3; uint8_t result = 0x00; uint8_t bitmask = (1 << bit_shift); /* Check rate identifier is supported */ err_code = self->get_rate_id(self); if (err_code <= 0) { return ERR_TRANSVR_NOTSUPPORT; } /* Update and check */ err_code = _check_by_mode(self, &_sfp_update_attr_soft_rs1, "sfp_get_soft_rs1"); if (err_code <0){ return err_code; } result = (self->soft_rs1 & bitmask); if (result == bitmask) { return 1; } if (result == 0) { return 0; } return ERR_TRANSVR_UNEXCPT; } int sfp_get_transvr_temp(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_sfp_update_attr_curr_temp, "sfp_get_transvr_temp"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_temp[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return _common_count_temp(self->curr_temp[0], self->curr_temp[1], buf_p); } int sfp_get_transvr_voltage(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_sfp_update_attr_curr_voltage, "sfp_get_transvr_voltage"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_voltage[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 Volt */ return _common_count_voltage(self->curr_voltage[0], self->curr_voltage[1], buf_p); } int sfp_get_transvr_tx_bias(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_sfp_update_attr_curr_tx_bias, "sfp_get_transvr_tx_bias"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 mA */ return _common_count_tx_bias(self->curr_tx_bias[0], self->curr_tx_bias[1], buf_p); } int sfp_get_transvr_tx_power(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_sfp_update_attr_curr_tx_power, "sfp_get_transvr_tx_power"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 mW */ return _common_count_tx_power(self->curr_tx_power[0], self->curr_tx_power[1], buf_p); } int sfp_get_transvr_rx_power(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_sfp_update_attr_curr_rx_power, "sfp_get_transvr_rx_power"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 mW */ return _common_count_rx_power(self->curr_rx_power[0], self->curr_rx_power[0], buf_p); } int sfp_get_transvr_rx_em(struct transvr_obj_s *self, char *buf_p) { int limt = 8; int err = DEBUG_TRANSVR_INT_VAL; err = _check_by_mode(self, &_sfp_update_attr_rx_em, "sfp_get_transvr_rx_em"); if (err < 0) { return snprintf(buf_p, limt, "%d\n", err); } if ((self->tx_eq[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return snprintf(buf_p, limt, "0x%02x\n", self->rx_em[0]); } int sfp_get_transvr_tx_eq(struct transvr_obj_s *self, char *buf_p) { int limt = 8; int err = DEBUG_TRANSVR_INT_VAL; err = _check_by_mode(self, &_sfp_update_attr_tx_eq, "sfp_get_transvr_tx_eq"); if (err < 0) { return snprintf(buf_p, limt, "%d\n", err); } if ((self->tx_eq[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return snprintf(buf_p, limt, "0x%02x\n", self->tx_eq[0]); } int _sfp_get_comp_extended(struct transvr_obj_s *self) { /* Address: A0h / 36 * Reference: SFF-8024 TABLE 4-4 */ if ((self->state == STATE_TRANSVR_CONNECTED) || (self->state == STATE_TRANSVR_INIT) ) { return (int)(self->transvr_comp_ext); } return ERR_TRANSVR_ABNORMAL; } int __sfp_get_comp_attr(struct transvr_obj_s *self, int array_offset) { /* SFP Specification Compliance: A0h / 3-10 * transvr_comp[0-7] = 3 - 10 */ if ((self->state == STATE_TRANSVR_CONNECTED) || (self->state == STATE_TRANSVR_INIT) ) { return (int)(self->transvr_comp[array_offset]); } return ERR_TRANSVR_ABNORMAL; } int _sfp_get_comp_10g_eth_comp(struct transvr_obj_s *self) { /* transvr_comp[0] = address A0h / 3 * * 3 7: 10G Base-ER * 3 6: 10GBASE-LRM * 3 5: 10GBASE-LR * 3 4: 10GBASE-SR */ int bitmask = 0xf0; /* 11110000 */ return (__sfp_get_comp_attr(self, 0) & bitmask); } int _sfp_get_comp_1g_eth_comp(struct transvr_obj_s *self) { /* transvr_comp[3] = address A0h / 6 * * 6 7: BASE-PX *3 * 6 6: BASE-BX10 *3 * 6 5: 100BASE-FX * 6 4: 100BASE-LX/LX10 * 6 3: 1000BASE-T * 6 2: 1000BASE-CX * 6 1: 1000BASE-LX *3 * 6 0: 1000BASE-SX */ return __sfp_get_comp_attr(self, 3); } int _sfp_get_cable_tech(struct transvr_obj_s *self) { /* transvr_comp[5] = address A0h / 8 * * 8 3: Active Cable *8 * 8 2: Passive Cable *8 */ int bitmask = 0x0c; /* 00001100 */ return (__sfp_get_comp_attr(self, 5) & bitmask); } int sfp_get_comp_eth_1(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_transvr_comp, "sfp_get_comp_eth_1"); if (err_code < 0){ return err_code; } return _sfp_get_comp_1g_eth_comp(self); } int sfp_get_comp_eth_10(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_transvr_comp, "sfp_get_comp_eth_10"); if (err_code < 0){ return err_code; } return _sfp_get_comp_10g_eth_comp(self); } int _sfp_get_connector_type(struct transvr_obj_s *self) { /* Address: A0h / 2 * Reference: SFF-8024 TABLE 4-3 */ if ((self->state == STATE_TRANSVR_CONNECTED) || (self->state == STATE_TRANSVR_INIT) ) { return (int)(self->connector); } return ERR_TRANSVR_ABNORMAL; } int sfp_get_wavelength(struct transvr_obj_s *self, char *buf_p) { /* [Note] Optical and Cable Variants Specification Compliance (SFF-8472) * [Addr] A0h, Bytes 60-61 * [Note] For optical variants, as defined by having zero's in A0h Byte 8 * bits 2 and 3, Bytes 60 and 61 denote nominal transmitter output * wavelength at room temperature. 16 bit value with byte 60 as high * order byte and byte 61 as low order byte. The laser wavelength is * equal to the 16 bit integer value in nm. This field allows the user * to read the laser wavelength directly, so it is not necessary to * infer it from the Transceiver Codes A0h Bytes 3 to 10 (see Table * 5-3). This also allows specification of wavelengths not covered * in the Transceiver Codes, such as those used in coarse WDM systems. * * For passive and active cable variants, a value of 00h for both A0h * Byte 60 and Byte 61 denotes laser wavelength or cable specification * compliance is unspecified. */ int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_common_update_attr_wavelength, "common_get_wavelength"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->wavelength[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* unit: 1 um */ return snprintf(buf_p, lmax, "%d\n", _common_count_wavelength(self, self->wavelength[0], self->wavelength[1])); } int __qsfp_get_power_cls(struct transvr_obj_s *self, int direct_access){ int err_code; uint8_t detect_val; /* Detect and Update power class attribute */ if (direct_access){ err_code = _check_by_mode(self, &_common_update_attr_extended_id, "__qsfp_get_power_cls"); } else { err_code = self->ext_id; } if (err_code <0){ return err_code; } if (err_code == DEBUG_TRANSVR_HEX_VAL){ return ERR_TRANSVR_UPDATE_FAIL; } /* Clean data */ detect_val = self->ext_id; SWP_BIT_CLEAR(detect_val, 2); /* Bit2: CDR RX present */ SWP_BIT_CLEAR(detect_val, 3); /* Bit3: CDR TX present */ SWP_BIT_CLEAR(detect_val, 4); /* Bit4: CLEI present */ SWP_BIT_CLEAR(detect_val, 5); /* Bit5: reserved */ /* Identify power class */ switch (detect_val) { case 0: /* Class_1: 00000000 */ return 1; case 64: /* Class_2: 01000000 */ return 2; case 128: /* Class_3: 10000000 */ return 3; case 192: /* Class_4: 11000000 */ return 4; case 1: /* Class_5: 00000001 */ case 193: /* Class_5: 11000001 */ return 5; case 2: /* Class_6: 00000010 */ case 194: /* Class_6: 11000010 */ return 6; case 3: /* Class_7: 00000011 */ case 195: /* Class_7: 11000011 */ return 7; default: break; } SWPS_INFO("%s: Detect undefined power class:%d\n", __func__, detect_val); return ERR_TRANSVR_UNDEFINED; } int qsfp_get_power_cls(struct transvr_obj_s *self) { return __qsfp_get_power_cls(self, 1); } int __qsfp_get_cdr_present(struct transvr_obj_s *self, int direct_access){ int retval; int BIT_SHIFT = 2; int BIT_MASK = 0x3; /* Detect and Update power class attribute */ if (direct_access) { retval = _check_by_mode(self, &_common_update_attr_extended_id, "__qsfp_get_cdr_present"); if (retval < 0){ return retval; } } retval = self->ext_id; if (retval == DEBUG_TRANSVR_HEX_VAL){ return ERR_TRANSVR_UPDATE_FAIL; } /* Clean data and return */ return (int)(retval >> BIT_SHIFT & BIT_MASK); } int qsfp_get_cdr_present(struct transvr_obj_s *self) { return __qsfp_get_cdr_present(self, 1); } int qsfp_get_cdr(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_qsfp_update_attr_cdr, "qsfp_get_cdr"); if (err_code <0){ return err_code; } return self->cdr; } int __qsfp_get_comp_attr(struct transvr_obj_s *self, int array_offset) { /* QSFP Specification Compliance: 00h / 131-138 * transvr_comp[0-7] = 131 - 138 */ if ((self->state == STATE_TRANSVR_CONNECTED) || (self->state == STATE_TRANSVR_INIT) ) { return (int)(self->transvr_comp[array_offset]); } return ERR_TRANSVR_ABNORMAL; } int _qsfp_get_comp_10_40_100_ethernet(struct transvr_obj_s *self) { /* transvr_comp[0] = address 00h / 131 * * 131 7: Extended: See section 6.3.23. The Extended Specification Compliance * Codes are maintained in the Transceiver Management section of SFF- * 8024. * 131 6: 10GBASE-LRM * 131 5: 10GBASE-LR * 131 4: 10GBASE-SR * 131 3: 40GBASE-CR4 * 131 2: 40GBASE-SR4 * 131 1: 40GBASE-LR4 * 131 0: 40G Active Cable (XLPPI) */ return __qsfp_get_comp_attr(self, 0); } int _qsfp_get_comp_sonet(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 132 7-3: Reserved * 132 2: OC 48, long reach * 132 1: OC 48, intermediate reach * 132 0: OC 48 short reach */ return __qsfp_get_comp_attr(self, 1); } int _qsfp_get_comp_sas_sata(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 133 7: SAS 24.0 Gb/s * 133 6: SAS 12.0 Gb/s * 133 5: SAS 6.0 Gb/s * 133 4: SAS 3.0 Gb/s * 133 3-0: Reserved */ return __qsfp_get_comp_attr(self, 2); } int _qsfp_get_comp_ethernet(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 134 7-4: Reserved * 134 3: 1000BASE-T * 134 2: 1000BASE-CX * 134 1: 1000BASE-LX * 134 0: 1000BASE-SX */ return __qsfp_get_comp_attr(self, 3); } int _qsfp_get_comp_fc_link_length(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 135 7: Very long distance (V) * 135 6: Short distance (S) * 135 5: Intermediate distance (I) * 135 4: Long distance (L) * 135 3: Medium (M) */ int mask = 0xFC; /* 11111100 */ return (__qsfp_get_comp_attr(self, 4) & mask); } int _qsfp_get_comp_fc_trans_tech(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 135 2: Reserved * 135 1: Longwave laser (LC) * 135 0: Electrical inter-enclosure (EL) * * 136 7: Electrical intra-enclosure * 136 6: Shortwave laser w/o OFC (SN) * 136 5: Shortwave laser w OFC (SL) * 136 4: Longwave Laser (LL) * 136 3-0: Reserved * * return value = [bit 8-15:addr 135][bit 0-7:addr 136] */ int mask_135 = 7; /* 00000111 */ int val_135 = (__qsfp_get_comp_attr(self, 4) & mask_135); int val_136 = __qsfp_get_comp_attr(self, 5); return ((val_135 << 7) + val_136); } int _qsfp_get_comp_fc_trans_media(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 137 7: Twin Axial Pair (TW) * 137 6: Shielded Twisted Pair (TP) * 137 5: Miniature Coax (MI) * 137 4: Video Coax (TV) * 137 3: Multi-mode 62.5 m (M6) * 137 2: Multi-mode 50 m (M5) * 137 1: Multi-mode 50 um (OM3) * 137 0: Single Mode (SM) */ return __qsfp_get_comp_attr(self, 6); } int _qsfp_get_comp_fc_speed(struct transvr_obj_s *self) { /* transvr_comp[1] = address 00h / 132 * * 138 7: 1200 MBps (per channel) * 138 6: 800 MBps * 138 5: 1600 MBps (per channel) * 138 4: 400 MBps * 138 3: 3200 MBps (per channel) * 138 2: 200 MBps * 138 1: Extended: See section 6.3.23. The Extended Specification * Compliance Codes are maintained in the Transceiver Management * section of SFF-8024. * 138 0: 100 MBps */ return __qsfp_get_comp_attr(self, 7); } int _qsfp_get_comp_extended(struct transvr_obj_s *self) { /* Address: 00h / 192 * Reference: SFF-8024 TABLE 4-4 */ if ((self->state == STATE_TRANSVR_CONNECTED) || (self->state == STATE_TRANSVR_INIT) ) { return (int)(self->transvr_comp_ext); } return ERR_TRANSVR_ABNORMAL; } int qsfp_get_comp_eth(struct transvr_obj_s *self){ int err_code = _check_by_mode(self, &_common_update_attr_transvr_comp, "qsfp_get_comp_eth"); if (err_code < 0){ return err_code; } return _qsfp_get_comp_ethernet(self); } int qsfp_get_comp_10_40(struct transvr_obj_s *self) { int err_code = _check_by_mode(self, &_common_update_attr_transvr_comp, "qsfp_get_comp_10_40"); if (err_code < 0){ return err_code; } return _qsfp_get_comp_10_40_100_ethernet(self); } int _qsfp_get_connector_type(struct transvr_obj_s *self) { /* Address: 00h / 130 * Reference: SFF-8024 TABLE 4-3 */ if ((self->state == STATE_TRANSVR_CONNECTED) || (self->state == STATE_TRANSVR_INIT) ) { return (int)(self->connector); } return ERR_TRANSVR_ABNORMAL; } int qsfp_get_transvr_temp(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_qsfp_update_attr_curr_temp, "qsfp_get_transvr_temp"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_temp[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return _common_count_temp(self->curr_temp[0], self->curr_temp[1], buf_p); } int qsfp_get_transvr_voltage(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_qsfp_update_attr_curr_voltage, "qsfp_get_transvr_voltage"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_voltage[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 Volt */ return _common_count_voltage(self->curr_voltage[0], self->curr_voltage[1], buf_p); } int qsfp_get_transvr_tx_eq(struct transvr_obj_s *self, char *buf_p) { int limt = 8; int err = DEBUG_TRANSVR_INT_VAL; err = _check_by_mode(self, &_qsfp_update_attr_tx_eq, "qsfp_get_transvr_tx_eq"); if (err < 0) { return snprintf(buf_p, limt, "%d\n", err); } if ((self->tx_eq[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return snprintf(buf_p, limt, "0x%02x%02x\n", self->tx_eq[0], self->tx_eq[1]); } int qsfp_get_transvr_rx_am(struct transvr_obj_s *self, char *buf_p) { int limt = 8; int err = DEBUG_TRANSVR_INT_VAL; err = _check_by_mode(self, &_qsfp_update_attr_rx_am, "qsfp_get_transvr_rx_am"); if (err < 0) { return snprintf(buf_p, limt, "%d\n", err); } if ((self->rx_am[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return snprintf(buf_p, limt, "0x%02x%02x\n", self->rx_am[0], self->rx_am[1]); } int qsfp_get_transvr_rx_em(struct transvr_obj_s *self, char *buf_p) { int limt = 8; int err = DEBUG_TRANSVR_INT_VAL; err = _check_by_mode(self, &_qsfp_update_attr_rx_em, "qsfp_get_transvr_rx_em"); if (err < 0) { return snprintf(buf_p, limt, "%d\n", err); } if ((self->rx_em[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, limt, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } return snprintf(buf_p, limt, "0x%02x%02x\n", self->rx_em[0], self->rx_em[1]); } int _qsfp_get_channel_diag(uint8_t *data_array, int (*count_func)(uint8_t high_byte, uint8_t low_byte, char *buf_p), char *ch_name, char *result_p) { int i, high, low; int len_max = 128; char ch_buf[4][16] = { DEBUG_TRANSVR_STR_VAL, DEBUG_TRANSVR_STR_VAL, DEBUG_TRANSVR_STR_VAL, DEBUG_TRANSVR_STR_VAL }; for (i=0; i<4; i++) { high = (i*2); low = ((i*2) + 1); count_func(data_array[high], data_array[low], ch_buf[i]); } return snprintf(result_p, len_max, "%s-%d:%s%s-%d:%s%s-%d:%s%s-%d:%s", ch_name, 1, ch_buf[0], ch_name, 2, ch_buf[1], ch_name, 3, ch_buf[2], ch_name, 4, ch_buf[3]); } int qsfp_get_soft_rx_los(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int mask = 0x0f; /* Bit 0 ~ Bit 3 */ int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_qsfp_update_attr_soft_rx_los, "qsfp_get_soft_rx_los"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } return snprintf(buf_p, lmax, "0x%02x\n", (self->rx_los & mask)); } int qsfp_get_soft_tx_disable(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int mask = 0x0f; /* Bit 0 ~ Bit 3 */ int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_qsfp_update_attr_soft_tx_disable, "qsfp_get_soft_tx_disable"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } return snprintf(buf_p, lmax, "0x%02x\n", (self->tx_disable & mask)); } int qsfp_get_soft_tx_fault(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int mask = 0x0f; /* Bit 0 ~ Bit 3 */ int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_qsfp_update_attr_soft_tx_fault, "qsfp_get_soft_tx_fault"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } return snprintf(buf_p, lmax, "0x%02x\n", (self->tx_fault & mask)); } int qsfp_get_auto_tx_disable(struct transvr_obj_s *self, char *buf_p) { if (self->auto_tx_disable == VAL_TRANSVR_FUNCTION_DISABLE) { return snprintf(buf_p, LEN_TRANSVR_S_STR, "%d\n", ERR_TRANSVR_FUNC_DISABLE); } return snprintf(buf_p, LEN_TRANSVR_S_STR, "0x%02x\n", self->auto_tx_disable); } int qsfp_get_transvr_tx_bias(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; char *ch_name = "TX"; err_code = _check_by_mode(self, &_qsfp_update_attr_curr_tx_bias, "qsfp_get_transvr_tx_bias"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_tx_bias[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 mA */ return _qsfp_get_channel_diag(self->curr_tx_bias, _common_count_tx_bias, ch_name, buf_p); } int qsfp_get_transvr_tx_power(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; char *ch_name = "TX"; err_code = _check_by_mode(self, &_qsfp_update_attr_curr_tx_power, "qsfp_get_transvr_tx_power"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_tx_power[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 mW */ return _qsfp_get_channel_diag(self->curr_tx_power, _common_count_tx_power, ch_name, buf_p); } int qsfp_get_transvr_rx_power(struct transvr_obj_s *self, char *buf_p) { int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; char *ch_name = "RX"; err_code = _check_by_mode(self, &_qsfp_update_attr_curr_rx_power, "qsfp_get_transvr_rx_power"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->curr_tx_power[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* Return Unit: 1 mW */ return _qsfp_get_channel_diag(self->curr_rx_power, _common_count_rx_power, ch_name, buf_p); } int qsfp_get_wavelength(struct transvr_obj_s *self, char *buf_p) { /* [Desc] Wavelength or Copper Cable Attenuation (SFF-8636) * [Addr] 00h 186-187 * [Note] * For optical free side devices, this parameter identifies the nominal * transmitter output wavelength at room temperature. This parameter is * a 16-bit hex value with Byte 186 as high order byte and Byte 187 as * low order byte. The laser wavelength is equal to the 16-bit integer value * divided by 20 in nm (units of 0.05 nm). This resolution should be adequate * to cover all relevant wavelengths yet provide enough resolution for all * expected DWDM applications. For accurate representation of controlled * wavelength applications, this value should represent the center of the * guaranteed wavelength range. * If the free side device is identified as copper cable these registers will * be used to define the cable attenuation. An indication of 0 dB attenuation * refers to the case where the attenuation is not known or is unavailable. * Byte 186 (00-FFh) is the copper cable attenuation at 2.5 GHz in units of 1 dB. * Byte 187 (00-FFh) is the copper cable attenuation at 5.0 GHz in units of 1 dB. */ int lmax = 8; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _check_by_mode(self, &_common_update_attr_wavelength, "common_get_wavelength"); if (err_code < 0) { return snprintf(buf_p, lmax, "%d\n", err_code); } if ((self->wavelength[0]) == DEBUG_TRANSVR_HEX_VAL) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_UPDATE_FAIL); } /* unit: 1 um */ return snprintf(buf_p, lmax, "%d\n", _common_count_wavelength(self, self->wavelength[0], self->wavelength[1])); } /* Public Function for Setup Features */ static int __sfp_set_soft_rs(struct transvr_obj_s *self, int input_val, int address, int page, int offset, int bit_shift, uint8_t *attr_p, char *caller, int show_err) { int retval = ERR_TRANSVR_UNEXCPT; int err_code = ERR_TRANSVR_UNEXCPT; char *err_msg = DEBUG_TRANSVR_STR_VAL; uint8_t update_val = (*attr_p); switch (input_val) { case 0: SWP_BIT_CLEAR(update_val, bit_shift); break; case 1: SWP_BIT_SET(update_val, bit_shift); break; default: retval = ERR_TRANSVR_UNEXCPT; err_code = ERR_TRANSVR_UNEXCPT; err_msg = "Exception occurs"; goto err_private_sfp_set_soft_rs_1; } err_code = _common_set_uint8_attr(self, address, page, offset, update_val, attr_p, caller, show_err); if (err_code < 0) { retval = err_code; err_msg = "Write data via i2c fail!"; goto err_private_sfp_set_soft_rs_1; } (*attr_p) = update_val; return 0; err_private_sfp_set_soft_rs_1: if (show_err) { SWPS_INFO("%s: %s :%d :%s\n :%d\n", __func__, err_msg, err_code, self->swp_name, input_val); } return retval; } static int _sfp_set_soft_rs(struct transvr_obj_s *self, int input_val, int address, int page, int offset, int bit_shift, int (*attr_update_func)(struct transvr_obj_s *self, int show_err), uint8_t *attr_p, char *caller, int show_err) { int retval = ERR_TRANSVR_UNEXCPT; int err_code = ERR_TRANSVR_UNEXCPT; char *err_msg = DEBUG_TRANSVR_STR_VAL; /* Check input value */ if ((input_val != 0) && (input_val != 1)){ retval = ERR_TRANSVR_BADINPUT; err_code = ERR_TRANSVR_BADINPUT; err_msg = "Input range incorrect!"; goto err_common_sfp_set_soft_rs_1; } /* Check rate identifier is supported */ err_code = self->get_rate_id(self); if (err_code <= 0) { switch (err_code) { case 0: retval = ERR_TRANSVR_NOTSUPPORT; err_msg = "Not support this feature"; break; case ERR_TRANSVR_UNINIT: retval = ERR_TRANSVR_UNINIT; err_msg = "Check CDR present fail!"; break; case ERR_TRANSVR_UNPLUGGED: retval = ERR_TRANSVR_UNPLUGGED; err_msg = "Transceiver unplugged!"; break; default: retval = err_code; err_msg = "Check Rate_ID fail!"; break; } goto err_common_sfp_set_soft_rs_1; } /* Check and update */ err_code = _check_by_mode(self, attr_update_func, caller); if ( (err_code < 0) || ((*attr_p) == DEBUG_TRANSVR_HEX_VAL) ){ retval = err_code; err_msg = "Get current value fail!"; goto err_common_sfp_set_soft_rs_1; } /* Generate and update value */ return __sfp_set_soft_rs(self, input_val, address, page, offset, bit_shift, attr_p, caller, show_err); err_common_sfp_set_soft_rs_1: if (show_err) { SWPS_INFO("%s: %s :%d :%s\n :%d\n", __func__, err_msg, err_code, self->swp_name, input_val); } return retval; } int sfp_set_soft_rs0(struct transvr_obj_s *self, int input_val) { /* Note: * SFP Soft Rate_Select Select RX ["RS(0)"] address * A2h, offset: 110, bit 3 */ int bit_shift = 3; int show_err = 1; return _sfp_set_soft_rs(self, input_val, self->eeprom_map_p->addr_soft_rs0, self->eeprom_map_p->page_soft_rs0, self->eeprom_map_p->offset_soft_rs0, bit_shift, &_sfp_update_attr_soft_rs0, &(self->soft_rs0), "sfp_set_soft_rs0", show_err); } int sfp_set_soft_rs1(struct transvr_obj_s *self, int input_val) { /* Note: * SFP Soft Rate_Select Select RX ["RS(1)"] address * A2h, offset: 118, bit 3 */ int bit_shift = 3; int show_err = 1; return _sfp_set_soft_rs(self, input_val, self->eeprom_map_p->addr_soft_rs1, self->eeprom_map_p->page_soft_rs1, self->eeprom_map_p->offset_soft_rs1, bit_shift, &_sfp_update_attr_soft_rs1, &(self->soft_rs1), "sfp_set_soft_rs1", show_err); } int __sfp_set_tx_eq(struct transvr_obj_s *self, int input, int show_e) { int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; uint8_t setv = DEBUG_TRANSVR_HEX_VAL; if ((input < 0) || (input > 0xFF)) { emsg = "input incorrect"; err = ERR_TRANSVR_BADINPUT; goto err_sfp_set_tx_eq; } setv = (uint8_t)input; if (self->tx_eq[0] == setv) { return 0; } err = _common_set_uint8_attr(self, self->eeprom_map_p->addr_tx_eq, self->eeprom_map_p->page_tx_eq, self->eeprom_map_p->offset_tx_eq, setv, &(self->tx_eq[0]), "_sfp_set_tx_eq", show_e); if (err < 0) { emsg = "set_uint8_attr fail"; goto err_sfp_set_tx_eq; } return 0; err_sfp_set_tx_eq: if (show_e) { SWPS_INFO("%s: %s :%d\n", __func__, emsg, input); } return err; } int _sfp_set_tx_eq(struct transvr_obj_s *self, int input, int show_e) { uint8_t tmp; int i = 0; int retry = 3; for (i=0; itx_eq[0]; if (_sfp_update_attr_tx_eq(self, show_e) < 0){ continue; } if (self->tx_eq[0] == tmp){ return 0; } } return ERR_TRANSVR_UPDATE_FAIL; } int sfp_set_tx_eq(struct transvr_obj_s *self, int input) { int err = _check_by_mode(self, &_sfp_update_attr_tx_eq, "sfp_set_tx_eq"); if (err < 0) { SWPS_DEBUG("%s: check fail :%d\n", __func__, err); return err; } return _sfp_set_tx_eq(self, input, 1); } int __sfp_set_rx_em(struct transvr_obj_s *self, int input, int show_e) { int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; uint8_t setv = DEBUG_TRANSVR_HEX_VAL; if ((input < 0) || (input > 0xFF)) { emsg = "input incorrect"; err = ERR_TRANSVR_BADINPUT; goto err_sfp_set_rx_em; } setv = (uint8_t)input; if (self->rx_em[0] == setv) { return 0; } err = _common_set_uint8_attr(self, self->eeprom_map_p->addr_rx_em, self->eeprom_map_p->page_rx_em, self->eeprom_map_p->offset_rx_em, setv, &(self->rx_em[0]), "_sfp_set_rx_em", show_e); if (err < 0) { emsg = "set_uint8_attr fail"; goto err_sfp_set_rx_em; } return 0; err_sfp_set_rx_em: if (show_e) { SWPS_INFO("%s: %s :%d\n", __func__, emsg, input); } return err; } int _sfp_set_rx_em(struct transvr_obj_s *self, int input, int show_e) { uint8_t tmp; int i = 0; int retry = 3; for (i=0; irx_em[0]; if (_sfp_update_attr_rx_em(self, show_e) < 0){ continue; } if (self->rx_em[0] == tmp){ return 0; } } return -1; } int sfp_set_rx_em(struct transvr_obj_s *self, int input) { int err = _check_by_mode(self, &_sfp_update_attr_rx_em, "sfp_set_rx_em"); if (err < 0) { SWPS_DEBUG("%s: check fail :%d\n", __func__, err); return err; } return _sfp_set_rx_em(self, input, 1); } static int __qsfp_set_cdr(struct transvr_obj_s *self, int input_val, int show_err) { uint8_t update_val; int CDR_FEATURE_SUPPORTED = 0x3; int retval = ERR_TRANSVR_UNEXCPT; int err_code = ERR_TRANSVR_UNEXCPT; char *err_msg = DEBUG_TRANSVR_STR_VAL; char *func_name = "__qsfp_set_cdr"; /* Check input value */ if ((input_val < 0) || (input_val > 0xff)){ retval = ERR_TRANSVR_BADINPUT; err_code = ERR_TRANSVR_BADINPUT; err_msg = "Input range incorrect!"; goto err_qsfp_set_cdr_1; } update_val = (uint8_t)input_val; /* Check CDR supported by transceiver */ err_code = qsfp_get_cdr_present(self); if (err_code < 0) { retval = err_code; switch (err_code) { case ERR_TRANSVR_UNINIT: err_msg = "Check CDR present fail!"; break; case ERR_TRANSVR_UNPLUGGED: err_msg = "Transceiver unplugged!"; break; default: err_msg = "Check CDR present fail!"; break; } goto err_qsfp_set_cdr_1; } if (err_code != CDR_FEATURE_SUPPORTED) { retval = ERR_TRANSVR_NOTSUPPORT; err_msg = "This transceiver not support CDR!"; goto err_qsfp_set_cdr_1; } /* Check and update */ err_code = _check_by_mode(self, &_qsfp_update_attr_cdr, func_name); if ( (err_code < 0) || (self->cdr == DEBUG_TRANSVR_HEX_VAL) ){ retval = err_code; err_msg = "Get current value fail!"; goto err_qsfp_set_cdr_1; } /* Write input value to transceiver */ return _common_set_uint8_attr(self, self->eeprom_map_p->addr_cdr, self->eeprom_map_p->page_cdr, self->eeprom_map_p->offset_cdr, update_val, &(self->cdr), func_name, show_err); err_qsfp_set_cdr_1: if (show_err) { SWPS_INFO("%s: %s :%d :%s\n :%d\n", __func__, err_msg, err_code, self->swp_name, input_val); } return retval; } int qsfp_set_cdr(struct transvr_obj_s *self, int input_val) { return __qsfp_set_cdr(self, input_val, 1); } int qsfp_set_soft_tx_disable(struct transvr_obj_s *self, int input_val) { int show_err = 1; int in_max = 0xf; /* 1111 */ int in_min = 0x0; /* 0000 */ int retval = DEBUG_TRANSVR_INT_VAL; int update_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; retval = _check_by_mode(self, &_qsfp_update_attr_soft_tx_disable, "qsfp_set_soft_tx_disable"); if (retval < 0) { snprintf(err_msg, 63, "Not ready. err:%d", retval); goto err_qsfp_set_soft_tx_disable; } if ((input_val > in_max) || (input_val < in_min) ){ retval = ERR_TRANSVR_BADINPUT; snprintf(err_msg, 63, "Input value:%d incorrect!", input_val); goto err_qsfp_set_soft_tx_disable; } if ((self->tx_disable & 0x0f) == input_val) { return 0; } update_val = ((self->tx_disable & 0xf0) & input_val); retval = _common_set_uint8_attr(self, self->eeprom_map_p->addr_tx_disable, self->eeprom_map_p->page_tx_disable, self->eeprom_map_p->offset_tx_disable, input_val, &(self->tx_disable), "qsfp_set_tx_disable", show_err); if (retval < 0) { snprintf(err_msg, 63, "_common_set_uint8_attr:%d fail!", retval); goto err_qsfp_set_soft_tx_disable; } return 0; err_qsfp_set_soft_tx_disable: SWPS_INFO("%s: %s :%s\n", __func__, err_msg, self->swp_name); return retval; } int _qsfp_set_auto_tx_disable(struct transvr_obj_s *self, uint8_t update) { uint8_t tx_enable = 0x0; int show_e = 1; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; /* Handle timing issues */ if (update != tx_enable) { /* Note: * Because there are some txvr has timing issues, * therefore we need to execute reset cycle first. * (enable -> other settings) */ err = _common_set_uint8_attr(self, self->eeprom_map_p->addr_tx_disable, self->eeprom_map_p->page_tx_disable, self->eeprom_map_p->offset_tx_disable, tx_enable, &(self->tx_disable), "_qsfp_set_auto_tx_disable", show_e); if (err < 0) { emsg = "I2C set reset value fail"; goto err_qsfp_set_auto_tx_disable; } mdelay(10); } /* Setup target value */ err = _common_set_uint8_attr(self, self->eeprom_map_p->addr_tx_disable, self->eeprom_map_p->page_tx_disable, self->eeprom_map_p->offset_tx_disable, self->auto_tx_disable, &(self->tx_disable), "_qsfp_set_auto_tx_disable", show_e); if (err < 0) { emsg = "I2C set target value fail"; goto err_qsfp_set_auto_tx_disable; } /* Check and update */ err = _common_update_uint8_attr(self, self->eeprom_map_p->addr_tx_disable, self->eeprom_map_p->page_tx_disable, self->eeprom_map_p->offset_tx_disable, self->eeprom_map_p->length_tx_disable, &(self->tx_disable), "_qsfp_set_auto_tx_disable", show_e); if (err < 0) { emsg = "I2C get value fail"; goto err_qsfp_set_auto_tx_disable; } if (self->tx_disable != update) { emsg = "data not become effective"; goto err_qsfp_set_auto_tx_disable; } return 0; err_qsfp_set_auto_tx_disable: SWPS_DEBUG("%s: %s :%s\n", __func__, emsg, self->swp_name); return ERR_TRANSVR_UPDATE_FAIL; } int qsfp_set_auto_tx_disable(struct transvr_obj_s *self, int input_val) { int in_max = 0xf; /* 1111 */ int in_min = 0x0; /* 0000 */ int retval = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; /* Update settings*/ if (input_val == VAL_TRANSVR_FUNCTION_DISABLE) { emsg = "User disable auto tx_disable"; self->auto_tx_disable = VAL_TRANSVR_FUNCTION_DISABLE; goto out_qsfp_set_auto_tx_disable; } if ((input_val > in_max) || (input_val < in_min) ){ SWPS_INFO("%s: Input value:%d incorrect! :%s\n", __func__, input_val, self->swp_name); return ERR_TRANSVR_BADINPUT; } self->auto_tx_disable = input_val; /* Check current soft tx_disable */ retval = _check_by_mode(self, &_qsfp_update_attr_soft_tx_disable, "qsfp_set_auto_tx_disable"); switch (retval) { case 0: break; case ERR_TRANSVR_UNPLUGGED: emsg = "Doesn't need to update"; goto out_qsfp_set_auto_tx_disable; default: SWPS_INFO("%s: setup fail :%d :%s\n", __func__, retval, self->swp_name); return retval; } return _qsfp_set_auto_tx_disable(self, input_val); out_qsfp_set_auto_tx_disable: SWPS_DEBUG("%s: %s :%s :%d\n :%d", __func__, emsg, self->swp_name, input_val, retval); return 0; } int __qsfp_set_tx_eq(struct transvr_obj_s *self, int input, int show_e) { /* [Note] * 0x */ int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; uint8_t setv[2] = {0x00, 0x00}; if ((input < 0) || (input > 0xFFFF)) { emsg = "input incorrect"; err = ERR_TRANSVR_BADINPUT; goto err_qsfp_set_tx_eq; } setv[0] = (uint8_t)((input & 0xFF00) >> 8); setv[1] = (uint8_t)(input & 0xFF); if ((self->tx_eq[0] == setv[0]) && (self->tx_eq[1] == setv[1]) ) { return 0; } err = _common_set_uint8_array(self, self->eeprom_map_p->addr_tx_eq, self->eeprom_map_p->page_tx_eq, self->eeprom_map_p->offset_tx_eq, self->eeprom_map_p->length_tx_eq, setv, self->tx_eq, "_qsfp_set_tx_eq", show_e); if (err < 0) { emsg = "set_uint8_array fail"; goto err_qsfp_set_tx_eq; } return 0; err_qsfp_set_tx_eq: if (show_e) { SWPS_INFO("%s: %s :%d\n", __func__, emsg, input); } return err; } int _qsfp_set_tx_eq(struct transvr_obj_s *self, int input, int show_e) { int i = 0; int retry = 3; uint8_t tmp[2]; for (i=0; itx_eq[0]; tmp[1] = self->tx_eq[1]; if (_qsfp_update_attr_tx_eq(self, show_e) < 0){ continue; } if ((self->tx_eq[0] == tmp[0]) && (self->tx_eq[1] == tmp[1]) ){ return 0; } } return -1; } int qsfp_set_tx_eq(struct transvr_obj_s *self, int input) { int err = _check_by_mode(self, &_qsfp_update_attr_tx_eq, "qsfp_set_tx_eq"); if (err < 0) { SWPS_DEBUG("%s: check fail :%d\n", __func__, err); return err; } return _qsfp_set_tx_eq(self, input, 1); } int __qsfp_set_rx_am(struct transvr_obj_s *self, int input, int show_e) { /* [Note] * 0x */ int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; uint8_t setv[2] = {0x00, 0x00}; if ((input < 0) || (input > 0xFFFF)) { emsg = "input incorrect"; err = ERR_TRANSVR_BADINPUT; goto err_qsfp_set_rx_am; } setv[0] = (uint8_t)((input & 0xFF00) >> 8); setv[1] = (uint8_t)(input & 0xFF); if ((self->rx_am[0] == setv[0]) && (self->rx_am[1] == setv[1]) ) { return 0; } err = _common_set_uint8_array(self, self->eeprom_map_p->addr_rx_am, self->eeprom_map_p->page_rx_am, self->eeprom_map_p->offset_rx_am, self->eeprom_map_p->length_rx_am, setv, self->rx_am, "_qsfp_set_rx_am", show_e); if (err < 0) { emsg = "set_uint8_array fail"; goto err_qsfp_set_rx_am; } return 0; err_qsfp_set_rx_am: if (show_e) { SWPS_INFO("%s: %s :%d\n", __func__, emsg, input); } return err; } int _qsfp_set_rx_am(struct transvr_obj_s *self, int input, int show_e) { int i = 0; int retry = 3; uint8_t tmp[2]; for (i=0; irx_am[0]; tmp[1] = self->rx_am[1]; if (_qsfp_update_attr_rx_am(self, show_e) < 0){ continue; } if ((self->rx_am[0] == tmp[0]) && (self->rx_am[1] == tmp[1]) ){ return 0; } } return -1; } int qsfp_set_rx_am(struct transvr_obj_s *self, int input) { int err = _check_by_mode(self, &_qsfp_update_attr_rx_am, "qsfp_set_rx_am"); if (err < 0) { SWPS_DEBUG("%s: check fail :%d\n", __func__, err); return err; } return _qsfp_set_rx_am(self, input, 1); } int __qsfp_set_rx_em(struct transvr_obj_s *self, int input, int show_e) { /* [Note] * 0x */ int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; uint8_t setv[2] = {0x00, 0x00}; if ((input < 0) || (input > 0xFFFF)) { emsg = "input incorrect"; err = ERR_TRANSVR_BADINPUT; goto err_qsfp_set_rx_em; } setv[0] = (uint8_t)((input & 0xFF00) >> 8); setv[1] = (uint8_t)(input & 0xFF); if ((self->rx_em[0] == setv[0]) && (self->rx_em[1] == setv[1]) ) { return 0; } err = _common_set_uint8_array(self, self->eeprom_map_p->addr_rx_em, self->eeprom_map_p->page_rx_em, self->eeprom_map_p->offset_rx_em, self->eeprom_map_p->length_rx_em, setv, self->rx_em, "_qsfp_set_rx_em", show_e); if (err < 0) { emsg = "set_uint8_array fail"; goto err_qsfp_set_rx_em; } return 0; err_qsfp_set_rx_em: if (show_e) { SWPS_INFO("%s: %s :%d\n", __func__, emsg, input); } return err; } int _qsfp_set_rx_em(struct transvr_obj_s *self, int input, int show_e) { int i = 0; int retry = 3; uint8_t tmp[2]; for (i=0; irx_em[0]; tmp[1] = self->rx_em[1]; if (_qsfp_update_attr_rx_em(self, show_e) < 0){ continue; } if ((self->rx_em[0] == tmp[0]) && (self->rx_em[1] == tmp[1]) ){ return 0; } } return -1; } int qsfp_set_rx_em(struct transvr_obj_s *self, int input) { int err = _check_by_mode(self, &_qsfp_update_attr_rx_em, "qsfp_set_rx_em"); if (err < 0) { SWPS_DEBUG("%s: check fail :%d\n", __func__, err); return err; } return _qsfp_set_rx_em(self, input, 1); } int common_transvr_dump(struct transvr_obj_s* self){ char *type_name = "Undefined"; if (TRANSVR_INFO_DUMP_ENABLE != 1) { return 0; } switch (self->type) { case TRANSVR_TYPE_SFP: type_name = STR_TRANSVR_SFP; break; case TRANSVR_TYPE_QSFP: type_name = STR_TRANSVR_QSFP; break; case TRANSVR_TYPE_QSFP_PLUS: type_name = STR_TRANSVR_QSFP_PLUS; break; case TRANSVR_TYPE_QSFP_28: type_name = STR_TRANSVR_QSFP28; break; case TRANSVR_TYPE_FAKE: type_name = "FAKE"; goto ok_common_transvr_dump; case TRANSVR_TYPE_UNPLUGGED: type_name = "UNPLUGGED"; goto err_common_transvr_dump; case TRANSVR_TYPE_INCONSISTENT: type_name = "INCONSISTENT"; goto err_common_transvr_dump; case TRANSVR_TYPE_ERROR: type_name = "ERROR"; goto err_common_transvr_dump; default: type_name = "UNEXPECTED"; goto err_common_transvr_dump; } printk(KERN_INFO "[SWPS] Dump %s information:\n", self->swp_name); printk(KERN_INFO " |- :%s\n", type_name); printk(KERN_INFO " |- :%s\n", self->vendor_name); printk(KERN_INFO " |- :%s\n", self->vendor_pn); printk(KERN_INFO " |- :%s\n", self->vendor_rev); printk(KERN_INFO " |- :%s\n", self->vendor_sn); printk(KERN_INFO " |- :0x%02x\n", self->br); printk(KERN_INFO " |- :0x%02x\n", self->comp_rev); printk(KERN_INFO " |- :%d\n", self->len_om1); printk(KERN_INFO " |- :%d\n", self->len_om2); printk(KERN_INFO " |- :%d\n", self->len_om3); printk(KERN_INFO " |- :%d\n", self->len_om4); return 0; ok_common_transvr_dump: SWPS_INFO("%s: %s is %s\n", __func__, self->swp_name, type_name); return 0; err_common_transvr_dump: SWPS_INFO("%s: %s is %s\n", __func__, self->swp_name, type_name); return -1; } int sfp_transvr_dump(struct transvr_obj_s* self) { if (TRANSVR_INFO_DUMP_ENABLE != 1) { return 0; } if (common_transvr_dump(self) < 0) { return -1; } printk(KERN_INFO " |- :%d\n", self->len_sm); printk(KERN_INFO " |- :%d\n", self->len_smf); printk(KERN_INFO " '- :0x%02x\n", self->rate_id); return 0; } int qsfp_transvr_dump(struct transvr_obj_s* self) { if (TRANSVR_INFO_DUMP_ENABLE != 1) { return 0; } if (common_transvr_dump(self) < 0) { return -1; } printk(KERN_INFO " |- :%d\n", self->len_smf); printk(KERN_INFO " '- :Class_%d\n", __qsfp_get_power_cls(self, 0)); return 0; } int fake_transvr_dump(struct transvr_obj_s* self) { printk(KERN_INFO "[SWPS] Dump transceiver information: %s\n", self->swp_name); printk(KERN_INFO " |- :FAKE\n"); printk(KERN_INFO " |- :FAKE_VENDER_NAME\n"); printk(KERN_INFO " |- :FAKE_VENDER_PN\n"); printk(KERN_INFO " |- :FAKE_VENDER_REV\n"); printk(KERN_INFO " |- :FAKE_VENDER_SN\n"); printk(KERN_INFO " |- :0x99\n"); printk(KERN_INFO " |- :99\n"); printk(KERN_INFO " |- :99\n"); printk(KERN_INFO " |- :99\n"); printk(KERN_INFO " |- :99\n"); printk(KERN_INFO " |- :99\n"); printk(KERN_INFO " |- :99\n"); printk(KERN_INFO " '- :0x99\n"); return 0; } /* ========== Object functions for fake type ========== */ int fake_transvr_update(struct transvr_obj_s *self, int show_err){ self->state = STATE_TRANSVR_CONNECTED; return 0; } int fake_get_binary(struct transvr_obj_s *self){ return 1; } int fake_get_int(struct transvr_obj_s *self){ return 99; } int fake_get_hex(struct transvr_obj_s *self){ return 0x0f; } int fake_get_str(struct transvr_obj_s *self, char *buf) { return snprintf(buf, 16, "fake_get_str\n"); } int fake_set_int(struct transvr_obj_s *self, int input){ SWPS_INFO("%s: %d\n", __func__, input); return 0; } int fake_set_hex(struct transvr_obj_s *self, int input){ SWPS_INFO("%s: 0x%02x\n", __func__, input); return 0; } /* ========== Object functions for unsupported ========== */ int unsupported_get_func(struct transvr_obj_s *self){ return ERR_TRANSVR_NOTSUPPORT; } int unsupported_get_func2(struct transvr_obj_s *self, char *buf_p) { int len = snprintf(buf_p, 8, "%d\n", ERR_TRANSVR_NOTSUPPORT); return len; } int unsupported_set_func(struct transvr_obj_s *self, int input_val){ return ERR_TRANSVR_NOTSUPPORT; } /* ========== Object functions for long term task ========== * * [Note] * SWPS transceiver worker is likely the green-thread (coroutine). * Due to resource and performance considerations. SWPS run all * features in one kthread at the same time, and handle by it self. */ /* For Transceiver Task Handling */ static struct transvr_worker_s * transvr_task_get(struct transvr_obj_s *self, char *func_name) { struct transvr_worker_s *curr_p = self->worker_p; while(curr_p != NULL){ if (strcmp((curr_p->func_name), func_name) == 0 ) { return curr_p; } curr_p = curr_p->next_p; } return NULL; } static struct transvr_worker_s* transvr_task_creat(struct transvr_obj_s *self, int (*main_task)(struct transvr_worker_s *task), int (*post_task)(struct transvr_worker_s *task), char *caller) { struct transvr_worker_s *task_p = NULL; struct transvr_worker_s *curr_p = NULL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; /* Check task not exist */ task_p = transvr_task_get(self, caller); if (task_p) { snprintf(err_msg, sizeof(err_msg), "Task already created!"); goto err_transvr_task_creat; } /* Create task worker */ task_p = kzalloc(sizeof(struct transvr_worker_s), GFP_KERNEL); if (!task_p){ snprintf(err_msg, sizeof(err_msg), "kzalloc fail"); goto err_transvr_task_creat; } /* Setup task data */ task_p->transvr_p = self; task_p->next_p = NULL; task_p->trigger_time = 0; task_p->retry = 1; task_p->state = STATE_T_TASK_INIT; task_p->main_task = main_task; task_p->post_task = post_task; task_p->p_data = NULL; snprintf(task_p->func_name, sizeof(task_p->func_name), "%s", caller); /* Setup Link List */ if (self->worker_p) { curr_p = self->worker_p; while(curr_p->next_p != NULL) { curr_p = curr_p->next_p; } curr_p->next_p = task_p; task_p->pre_p = curr_p; } else { self->worker_p = task_p; task_p->pre_p = NULL; } return task_p; err_transvr_task_creat: SWPS_ERR("%s: %s :%s :%s\n", __func__, err_msg, caller, self->swp_name); return NULL; } static void transvr_task_free_one(struct transvr_worker_s *task_p){ struct transvr_worker_s *pre_p = NULL; struct transvr_worker_s *next_p = NULL; if (task_p) { pre_p = task_p->pre_p; next_p = task_p->next_p; if ((pre_p) && (next_p)) { pre_p->next_p = next_p; next_p->pre_p = pre_p; } else if ((!pre_p) && (next_p)) { next_p->pre_p = NULL; } else if ((pre_p) && (!next_p)) { pre_p->next_p = NULL; } else if ((!pre_p) && (!next_p)) { task_p->transvr_p->worker_p = NULL; } else { SWPS_ERR("%s: Unexcept case!\n :%s", __func__, task_p->transvr_p->swp_name); } kfree(task_p->p_data); kfree(task_p); } } static void transvr_task_free_all(struct transvr_obj_s *self) { struct transvr_worker_s *curr_p = NULL; struct transvr_worker_s *next_p = NULL; if (self->worker_p) { curr_p = self->worker_p; while(curr_p) { next_p = curr_p->next_p; transvr_task_free_one(curr_p); curr_p = next_p; } self->worker_p = NULL; } } static int _transvr_task_run_main(struct transvr_worker_s *task_p) { int retval = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; if (!task_p){ snprintf(err_msg, sizeof(err_msg), "main_task is NULL!"); goto main_transvr_task_err; } if ((task_p->trigger_time) == 0){ goto main_transvr_task_run; } if (time_before(jiffies, task_p->trigger_time)){ goto main_transvr_task_wait; } goto main_transvr_task_run; main_transvr_task_run: if (task_p->retry != VAL_TRANSVR_TASK_RETRY_FOREVER) { task_p->retry -= 1; } retval = task_p->main_task(task_p); if (retval < 0) { if (task_p->retry > 0) { task_p->state = STATE_T_TASK_WAIT; return EVENT_TRANSVR_TASK_WAIT; } snprintf(err_msg, sizeof(err_msg), "Run main_task fail!"); goto main_transvr_task_err; } goto main_transvr_task_identify; main_transvr_task_identify: switch (retval) { case EVENT_TRANSVR_TASK_WAIT: task_p->state = STATE_T_TASK_WAIT; return EVENT_TRANSVR_TASK_WAIT; case EVENT_TRANSVR_TASK_DONE: task_p->state = STATE_T_TASK_DONE; return EVENT_TRANSVR_TASK_DONE; default: break; } snprintf(err_msg, sizeof(err_msg), "Run main_task fail!"); goto main_transvr_task_err; main_transvr_task_wait: task_p->state = STATE_T_TASK_WAIT; return EVENT_TRANSVR_TASK_WAIT; main_transvr_task_err: task_p->state = STATE_T_TASK_FAIL; SWPS_INFO("%s: %s :%d :%s\n", __func__, err_msg, retval, task_p->transvr_p->swp_name); return EVENT_TRANSVR_INIT_FAIL; } static int _transvr_task_run_post(struct transvr_worker_s *task_p) { char err_msg[64] = DEBUG_TRANSVR_STR_VAL; if ((task_p->post_task) == NULL) { return EVENT_TRANSVR_TASK_DONE; } switch (task_p->state) { case STATE_T_TASK_WAIT: case STATE_T_TASK_INIT: goto post_transvr_task_wait; case STATE_T_TASK_DONE: case STATE_T_TASK_FAIL: goto post_transvr_task_run; default: break; } snprintf(err_msg, sizeof(err_msg), "Unexcept task state"); goto post_transvr_task_err; post_transvr_task_run: task_p->post_task(task_p); return EVENT_TRANSVR_TASK_DONE; post_transvr_task_wait: return EVENT_TRANSVR_TASK_WAIT; post_transvr_task_err: SWPS_INFO("%s: %s :%d :%s\n", __func__, err_msg, task_p->state, task_p->transvr_p->swp_name); return EVENT_TRANSVR_TASK_FAIL; } static int transvr_task_run_one(struct transvr_worker_s *task_p) { int retval_main = DEBUG_TRANSVR_INT_VAL; int retval_post = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; retval_main = _transvr_task_run_main(task_p); if (retval_main < 0) { snprintf(err_msg, sizeof(err_msg), "Execute main_task fail!"); goto err_transvr_task_run_one; } retval_post = _transvr_task_run_post(task_p); if (retval_post < 0) { snprintf(err_msg, sizeof(err_msg), "Execute post_task fail!"); goto err_transvr_task_run_one; } return retval_main; err_transvr_task_run_one: SWPS_INFO("%s: %s
:%d :%d :%s :%s\n", __func__, err_msg, retval_main, retval_post, task_p->func_name, task_p->transvr_p->swp_name); return EVENT_TRANSVR_TASK_FAIL; } static int transvr_task_run_all(struct transvr_obj_s *self) { int haserr = 0; int retval = DEBUG_TRANSVR_INT_VAL; struct transvr_worker_s *curr_p = NULL; struct transvr_worker_s *next_p = NULL; if ((self->worker_p) == NULL) { return EVENT_TRANSVR_TASK_DONE; } curr_p = self->worker_p; while (curr_p != NULL) { next_p = curr_p->next_p; retval = transvr_task_run_one(curr_p); if (curr_p->retry == VAL_TRANSVR_TASK_RETRY_FOREVER) { curr_p = next_p; continue; } switch (retval) { case EVENT_TRANSVR_TASK_WAIT: break; case EVENT_TRANSVR_TASK_DONE: transvr_task_free_one(curr_p); break; case EVENT_TRANSVR_TASK_FAIL: default: haserr = 1; transvr_task_free_one(curr_p); break; } curr_p = next_p; } if (haserr) { return EVENT_TRANSVR_TASK_FAIL; } return EVENT_TRANSVR_TASK_DONE; } static void transvr_task_set_delay(struct transvr_worker_s *task_p, unsigned long delay_msec) { task_p->trigger_time = (jiffies + (delay_msec * (HZ/1000))); } static void transvr_task_set_retry(struct transvr_worker_s *task_p, unsigned long retry_times) { task_p->retry = retry_times; } /* For Transceiver Post Task */ int taskfunc_post_do_nothing(struct transvr_worker_s *task_p) { return EVENT_TRANSVR_TASK_DONE; } int taskfunc_post_handle_task_state(struct transvr_worker_s *task_p) { struct transvr_obj_s* tp = task_p->transvr_p; switch (task_p->state) { case STATE_T_TASK_INIT: case STATE_T_TASK_WAIT: return EVENT_TRANSVR_TASK_WAIT; case STATE_T_TASK_DONE: tp->state = STATE_TRANSVR_CONNECTED; tp->send_uevent(tp, KOBJ_ADD); return EVENT_TRANSVR_TASK_DONE; case STATE_T_TASK_FAIL: tp->state = STATE_TRANSVR_UNEXCEPTED; return EVENT_TRANSVR_TASK_FAIL; default: break; } return EVENT_TRANSVR_TASK_FAIL; } /* For Transceiver Main Task */ int _taskfunc_sfp_setup_soft_rs(struct transvr_worker_s *task_p, int input_val, int address, int page, int offset, int bit_shift, uint8_t *attr_p, char *caller) { int show_err = 0; int err_code = DEBUG_TRANSVR_INT_VAL; char *err_str = DEBUG_TRANSVR_STR_VAL; char *func_str = "_taskfunc_sfp_setup_soft_rs"; err_code = _sfp_update_attr_soft_rs0(task_p->transvr_p, 0); if (err_code < 0) { err_str = "Get current soft_rs0 fail!"; goto err_taskfunc_sfp_setup_soft_rs_1; } err_code = __sfp_set_soft_rs(task_p->transvr_p, input_val, address, page, offset, bit_shift, attr_p, caller, show_err); if (err_code < 0) { err_str = "Get current soft_rs0 fail!"; goto err_taskfunc_sfp_setup_soft_rs_1; } return EVENT_TRANSVR_TASK_DONE; err_taskfunc_sfp_setup_soft_rs_1: if ((task_p->retry) == 0) { SWPS_INFO("%s: %s :%s :%d :%d\n", func_str, err_str, task_p->transvr_p->swp_name, input_val, err_code); } return EVENT_TRANSVR_TASK_FAIL; } int __taskfunc_sfp_setup_hard_rs(struct transvr_worker_s *task_p, int input_val, int (*get_func)(struct ioexp_obj_s *self, int virt_offset), int (*set_func)(struct ioexp_obj_s *self, int virt_offset, int input_val)) { int err_val = EVENT_TRANSVR_EXCEP_EXCEP; char *err_str = DEBUG_TRANSVR_STR_VAL; err_val = get_func(task_p->transvr_p->ioexp_obj_p, task_p->transvr_p->ioexp_virt_offset); if (err_val < 0) { if (err_val == ERR_IOEXP_NOTSUPPORT) { return EVENT_TRANSVR_TASK_DONE; } err_str = "Get current hard_rs fail!"; goto err_p_taskfunc_sfp_setup_hard_rs_1; } if (err_val == input_val) { return EVENT_TRANSVR_TASK_DONE; } err_val = set_func(task_p->transvr_p->ioexp_obj_p, task_p->transvr_p->ioexp_virt_offset, input_val); if (err_val < 0) { err_str = "Setup hard_rs fail!"; goto err_p_taskfunc_sfp_setup_hard_rs_1; } return EVENT_TRANSVR_TASK_DONE; err_p_taskfunc_sfp_setup_hard_rs_1: if ((task_p->retry) == 0) { SWPS_INFO("%s: %s :%s :%d :%d\n", __func__, err_str, task_p->transvr_p->swp_name, input_val, err_val); } return EVENT_TRANSVR_TASK_FAIL; } int _taskfunc_sfp_setup_hard_rs0(struct transvr_worker_s *task_p, int input_val) { return __taskfunc_sfp_setup_hard_rs(task_p, input_val, task_p->transvr_p->ioexp_obj_p->get_hard_rs0, task_p->transvr_p->ioexp_obj_p->set_hard_rs0); } int _taskfunc_sfp_setup_hard_rs1(struct transvr_worker_s *task_p, int input_val) { return __taskfunc_sfp_setup_hard_rs(task_p, input_val, task_p->transvr_p->ioexp_obj_p->get_hard_rs1, task_p->transvr_p->ioexp_obj_p->set_hard_rs1); } int _taskfunc_sfp_setup_rs0(struct transvr_worker_s *task_p, int input_val) { int bit_shift = 3; int old_val = DEBUG_TRANSVR_INT_VAL; int err_val = EVENT_TRANSVR_EXCEP_EXCEP; char *err_str = DEBUG_TRANSVR_STR_VAL; char *func_str = "_taskfunc_sfp_setup_rs0"; err_val = _taskfunc_sfp_setup_hard_rs0(task_p, input_val); if (err_val < 0) { err_str = "Setup hard_rs0 fail!"; goto err_private_taskfunc_sfp_setup_rs0_1; } old_val = err_val; err_val = _taskfunc_sfp_setup_soft_rs(task_p, input_val, task_p->transvr_p->eeprom_map_p->addr_soft_rs0, task_p->transvr_p->eeprom_map_p->page_soft_rs0, task_p->transvr_p->eeprom_map_p->offset_soft_rs0, bit_shift, &(task_p->transvr_p->soft_rs0), func_str); if (err_val < 0) { err_str = "Setup soft_rs0 fail!"; goto err_private_taskfunc_sfp_setup_rs0_1; } return EVENT_TRANSVR_TASK_DONE; err_private_taskfunc_sfp_setup_rs0_1: if ((task_p->retry) == 0) { SWPS_INFO("%s: %s :%s :%d :%d\n", func_str, err_str, task_p->transvr_p->swp_name, input_val, err_val); } _taskfunc_sfp_setup_hard_rs0(task_p, old_val); return EVENT_TRANSVR_TASK_FAIL; } int _taskfunc_sfp_setup_rs1(struct transvr_worker_s *task_p, int input_val) { int bit_shift = 3; int old_val = DEBUG_TRANSVR_INT_VAL; int err_val = EVENT_TRANSVR_EXCEP_EXCEP; char *err_str = DEBUG_TRANSVR_STR_VAL; char *func_str = "_taskfunc_sfp_setup_rs1"; err_val = _taskfunc_sfp_setup_hard_rs1(task_p, input_val); if (err_val < 0) { err_str = "Setup hard_rs1 fail!"; goto err_private_taskfunc_sfp_setup_rs1_1; } old_val = err_val; err_val = _taskfunc_sfp_setup_soft_rs(task_p, input_val, task_p->transvr_p->eeprom_map_p->addr_soft_rs1, task_p->transvr_p->eeprom_map_p->page_soft_rs1, task_p->transvr_p->eeprom_map_p->offset_soft_rs1, bit_shift, &(task_p->transvr_p->soft_rs1), func_str); if (err_val < 0) { err_str = "Setup soft_rs1 fail!"; goto err_private_taskfunc_sfp_setup_rs1_1; } return EVENT_TRANSVR_TASK_DONE; err_private_taskfunc_sfp_setup_rs1_1: if ((task_p->retry) == 0) { SWPS_INFO("%s: %s :%s :%d :%d\n", func_str, err_str, task_p->transvr_p->swp_name, input_val, err_val); } _taskfunc_sfp_setup_hard_rs1(task_p, old_val); return EVENT_TRANSVR_TASK_FAIL; } int taskfunc_sfp_setup_SFF8431_case1(struct transvr_worker_s *task_p) { /* SFF-8431 (8/4/2G Rx Rate_Select only) */ int update_val = 1; return _taskfunc_sfp_setup_rs0(task_p, update_val); } int taskfunc_sfp_setup_SFF8431_case2(struct transvr_worker_s *task_p) { /* SFF-8431 (8/4/2G Tx Rate_Select only) */ int update_val = 1; return _taskfunc_sfp_setup_rs1(task_p, update_val); } int taskfunc_sfp_setup_SFF8431_case3(struct transvr_worker_s *task_p) { /* SFF-8431 (8/4/2G Independent Rx & Tx Rate_select) */ int update_rs0 = 1; int update_rs1 = 1; int err_code = DEBUG_TRANSVR_INT_VAL; err_code = _taskfunc_sfp_setup_rs0(task_p, update_rs0); if (err_code < 0) { return err_code; } return _taskfunc_sfp_setup_rs1(task_p, update_rs1); } int taskfunc_sfp_handle_1g_rj45(struct transvr_worker_s *task_p) { /* Not all of platform support 0x56 for transceiver * external PHY, Support list as below: * => 1. Magnolia-PVT (PS: EVT & DVT not ready) */ int ext_phy_addr = 0x56; int ext_phy_page = -1; int ext_phy_offs = 0x11; int ext_phy_len = 1; int lstate_mask = 0x04; /* 00000100 */ int show_err = 0; int fail_retry = 5; int fail_delay = 1000; /* msec */ int err_code = DEBUG_TRANSVR_INT_VAL; uint8_t detect_val = DEBUG_TRANSVR_HEX_VAL; char err_str[64] = DEBUG_TRANSVR_STR_VAL; int *tmp_p = NULL; char *func_name = "taskfunc_sfp_handle_1g_rj45"; if (task_p->transvr_p->state != STATE_TRANSVR_CONNECTED) { return EVENT_TRANSVR_TASK_DONE; } if ( (task_p->transvr_p->info != TRANSVR_CLASS_BASE_T_1000) && (task_p->transvr_p->info != TRANSVR_CLASS_BASE_T_1000_up) ) { goto err_taskfunc_sfp_handle_1g_rj45_1; } err_code = _common_update_uint8_attr(task_p->transvr_p, ext_phy_addr, ext_phy_page, ext_phy_offs, ext_phy_len, &detect_val, func_name, show_err); if ( (err_code < 0) || (detect_val == DEBUG_TRANSVR_HEX_VAL) ) { snprintf(err_str, sizeof(err_str), "Detect external link status fail"); goto err_taskfunc_sfp_handle_1g_rj45_2; } if ((detect_val & lstate_mask) == lstate_mask) { goto ok_taskfunc_sfp_handle_1g_rj45_link_up; } goto ok_taskfunc_sfp_handle_1g_rj45_link_down; ok_taskfunc_sfp_handle_1g_rj45_link_up: /* Filter out noise */ if (!(task_p->p_data)) { tmp_p = kzalloc(sizeof(int), GFP_KERNEL); if (!tmp_p) { snprintf(err_str, sizeof(err_str), "kzalloc p_data fail"); goto err_taskfunc_sfp_handle_1g_rj45_2; } *tmp_p = TRANSVR_CLASS_BASE_T_1000_up; task_p->p_data = tmp_p; goto ok_taskfunc_sfp_handle_1g_rj45_done; } if ((*(int *)(task_p->p_data)) != TRANSVR_CLASS_BASE_T_1000_up) { kfree(task_p->p_data); task_p->p_data = NULL; snprintf(err_str, sizeof(err_str), "Internal error"); goto err_taskfunc_sfp_handle_1g_rj45_2; } task_p->transvr_p->info = TRANSVR_CLASS_BASE_T_1000_up; kfree(task_p->p_data); task_p->p_data = NULL; goto ok_taskfunc_sfp_handle_1g_rj45_done; ok_taskfunc_sfp_handle_1g_rj45_link_down: if (task_p->p_data) { kfree(task_p->p_data); task_p->p_data = NULL; } task_p->transvr_p->info = TRANSVR_CLASS_BASE_T_1000; goto ok_taskfunc_sfp_handle_1g_rj45_done; ok_taskfunc_sfp_handle_1g_rj45_done: if (task_p->retry != VAL_TRANSVR_TASK_RETRY_FOREVER) { transvr_task_set_retry(task_p, VAL_TRANSVR_TASK_RETRY_FOREVER); } return EVENT_TRANSVR_TASK_DONE; err_taskfunc_sfp_handle_1g_rj45_1: snprintf(err_str, sizeof(err_str), "Detect transceiver:%d not Base-T, remove task.", task_p->transvr_p->info); SWPS_INFO("%s: %s :%s\n", __func__, err_str, task_p->transvr_p->swp_name); transvr_task_set_retry(task_p, 0); return EVENT_TRANSVR_TASK_DONE; err_taskfunc_sfp_handle_1g_rj45_2: if (task_p->retry == VAL_TRANSVR_TASK_RETRY_FOREVER) { transvr_task_set_retry(task_p, fail_retry); } if ((task_p->retry) == 0) { /* Error case: * => In this case, SWPS will stop external Link state monitor features * and keeps transvr_p->info on TRANSVR_CLASS_BASE_T_1000_up. * Upper layer will see it always Linkup that because of these type of * transceiver has external phy, BCM chip see it as Loopback transceiver. */ SWPS_WARN("%s can not access external PHY of Base-T SFP transceiver\n", task_p->transvr_p->swp_name); task_p->transvr_p->info = TRANSVR_CLASS_BASE_T_1000_up; return EVENT_TRANSVR_TASK_DONE; } else { transvr_task_set_delay(task_p, fail_delay); } return EVENT_TRANSVR_TASK_FAIL; } int _taskfunc_qsfp_setup_power_mod(struct transvr_obj_s *self, int setup_val) { int curr_val = DEBUG_TRANSVR_INT_VAL; int err_val = DEBUG_TRANSVR_INT_VAL; char *err_msg = DEBUG_TRANSVR_STR_VAL; curr_val = self->ioexp_obj_p->get_lpmod(self->ioexp_obj_p, self->ioexp_virt_offset); if (curr_val < 0){ err_msg = "Get current value fail!"; goto err_private_taskfunc_qsfp_setup_power_mod_1; } if (curr_val == setup_val){ return EVENT_TRANSVR_TASK_DONE; } err_val = self->ioexp_obj_p->set_lpmod(self->ioexp_obj_p, self->ioexp_virt_offset, setup_val); if (err_val < 0){ err_msg = "Setup power mode fail!"; goto err_private_taskfunc_qsfp_setup_power_mod_1; } return EVENT_TRANSVR_TASK_DONE; err_private_taskfunc_qsfp_setup_power_mod_1: SWPS_INFO("%s: %s :%d :%d :%d\n", __func__, err_msg, err_val, curr_val, setup_val); return EVENT_TRANSVR_TASK_FAIL; } int taskfunc_qsfp_handle_tx_disable(struct transvr_worker_s *task_p) { int i = 0; int retry = 5; int delay_ms = 100; if (task_p->transvr_p->auto_tx_disable == VAL_TRANSVR_FUNCTION_DISABLE) { return EVENT_TRANSVR_TASK_DONE; } if (!_qsfp_is_implement_tx_disable(task_p->transvr_p)) { return EVENT_TRANSVR_TASK_DONE; } for (i=0; itransvr_p, task_p->transvr_p->auto_tx_disable) == EVENT_TRANSVR_TASK_DONE) { goto ok_taskfunc_qsfp_handle_tx_disable; } mdelay(delay_ms); } SWPS_INFO("%s auto setup tx_disable:0x%02x fail.\n", task_p->transvr_p->swp_name, task_p->transvr_p->auto_tx_disable); return EVENT_TRANSVR_INIT_FAIL; ok_taskfunc_qsfp_handle_tx_disable: SWPS_INFO("%s auto setup tx_disable:0x%02x ok.\n", task_p->transvr_p->swp_name, task_p->transvr_p->auto_tx_disable); return EVENT_TRANSVR_TASK_DONE; } int taskfunc_qsfp_set_hpmod(struct transvr_worker_s *task_p) { int err = DEBUG_TRANSVR_INT_VAL; int HIGH_POWER_MODE = 0; /* Handle power mode */ err = _taskfunc_qsfp_setup_power_mod(task_p->transvr_p, HIGH_POWER_MODE); if (err < 0) { SWPS_INFO("%s: setup hpmod fail :%d :%s\n", __func__, err, task_p->transvr_p->swp_name); return err; } /* Handle auto tx_disable * [Note] * => Because there are some transceiver have timing issues or * setup sequence issues, therefore we handle auto tx_disable * after handle power mode. */ mdelay(100); return taskfunc_qsfp_handle_tx_disable(task_p); } int taskfunc_qsfp_set_lpmod(struct transvr_worker_s *task_p) { int LOW_POWER_MODE = 1; return _taskfunc_qsfp_setup_power_mod(task_p->transvr_p, LOW_POWER_MODE); } static int initfunc_sfp_handle_multi_rate_mode(struct transvr_obj_s *self) { int task_retry = 3; int err_code = DEBUG_TRANSVR_INT_VAL; char *err_str = DEBUG_TRANSVR_STR_VAL; char *func_str = "sfp_handle_multi_rate_mode"; struct transvr_worker_s *task_p = NULL; switch (self->rate_id) { case 0x00: /* Unspecified */ case 0x03: /* Unspecified */ case 0x05: /* Unspecified */ case 0x07: /* Unspecified */ case 0x09: /* Unspecified */ case 0x0B: /* Unspecified */ case 0x0D: /* Unspecified */ case 0x0F: /* Unspecified */ goto sfp_handle_multi_rate_mode_4_unspecified; case 0x02: /* SFF-8431 (8/4/2G Rx Rate_Select only) */ task_p = transvr_task_creat(self, taskfunc_sfp_setup_SFF8431_case1, taskfunc_post_handle_task_state, func_str); goto sfp_handle_multi_rate_mode_4_sff8431; case 0x04: /* SFF-8431 (8/4/2G Tx Rate_Select only) */ task_p = transvr_task_creat(self, taskfunc_sfp_setup_SFF8431_case2, taskfunc_post_handle_task_state, func_str); goto sfp_handle_multi_rate_mode_4_sff8431; case 0x06: /* SFF-8431 (8/4/2G Independent Rx & Tx Rate_select) */ task_p = transvr_task_creat(self, taskfunc_sfp_setup_SFF8431_case3, taskfunc_post_handle_task_state, func_str); goto sfp_handle_multi_rate_mode_4_sff8431; case 0x01: /* SFF-8079 (4/2/1G Rate_Select & AS0/AS1) */ err_str = "SFF-8079 (4/2/1G Rate_Select & AS0/AS1)"; goto sfp_handle_multi_rate_mode_4_not_support; case 0x08: /* FC-PI-5 (16/8/4G Rx Rate_select only) * High=16G only, Low=8G/4G */ err_str = "FC-PI-5 (16/8/4G Rx Rate_select only)"; goto sfp_handle_multi_rate_mode_4_not_support; case 0x0A: /* FC-PI-5 (16/8/4G Independent Rx, Tx Rate_select) * High=16G only, Low=8G/4G */ err_str = "FC-PI-5 (16/8/4G Independent Rx, Tx Rate_select)"; goto sfp_handle_multi_rate_mode_4_not_support; case 0x0C: /* FC-PI-6 (32/16/8G Independent Rx, Tx Rate_Select) * High=32G only, Low = 16G/8G */ err_str = "FC-PI-6 (32/16/8G Independent Rx, Tx Rate_Select)"; goto sfp_handle_multi_rate_mode_4_not_support; case 0x0E: /* 10/8G Rx and Tx Rate_Select controlling the operation or * locking modes of the internal signal conditioner, retimer * or CDR, according to the logic table defined in Table 10-2, * High Bit Rate (10G) =9.95-11.3 Gb/s; Low Bit Rate (8G) = * 8.5 Gb/s. In this mode, the default value of bit 110.3 (Soft * Rate Select RS(0), Table 9-11) and of bit 118.3 (Soft Rate * Select RS(1), Table 10-1) is 1. */ err_str = "cable type: 0x0E"; goto sfp_handle_multi_rate_mode_4_not_support; default: err_str = "cable type: UNKNOW"; goto sfp_handle_multi_rate_mode_4_not_support; } sfp_handle_multi_rate_mode_4_sff8431: if (!task_p) { err_str = "Create task fail!"; goto sfp_handle_multi_rate_mode_4_fail_1; } transvr_task_set_retry(task_p, task_retry); return EVENT_TRANSVR_TASK_WAIT; sfp_handle_multi_rate_mode_4_unspecified: return EVENT_TRANSVR_TASK_DONE; sfp_handle_multi_rate_mode_4_not_support: SWPS_INFO("%s: Does not support %s :%s :0x%02x\n", func_str, err_str, self->swp_name, self->rate_id); return EVENT_TRANSVR_TASK_DONE; sfp_handle_multi_rate_mode_4_fail_1: SWPS_INFO("%s: %s :%s :0x%02x, :%d\n", func_str, err_str, self->swp_name, self->rate_id, err_code); return EVENT_TRANSVR_INIT_FAIL; } static int initfunc_sfp_handle_1g_rj45(struct transvr_obj_s *self) { struct transvr_worker_s *task_p = NULL; int detect_cls = DEBUG_TRANSVR_INT_VAL; char err_str[64] = DEBUG_TRANSVR_STR_VAL; char *func_str = "initfunc_sfp_handle_1g_rj45"; if (self->info == TRANSVR_CLASS_BASE_T_1000) { task_p = transvr_task_creat(self, taskfunc_sfp_handle_1g_rj45, taskfunc_post_do_nothing, func_str); if (!task_p) { snprintf(err_str, sizeof(err_str), "Create task fail"); goto err_initfunc_sfp_handle_1g_rj45; } transvr_task_set_retry(task_p, VAL_TRANSVR_TASK_RETRY_FOREVER); } return EVENT_TRANSVR_TASK_DONE; err_initfunc_sfp_handle_1g_rj45: SWPS_INFO("%s: %s :%s :%d\n", __func__, err_str, self->swp_name, detect_cls); return EVENT_TRANSVR_TASK_FAIL; } static int initfunc_qsfp_handle_power_mode(struct transvr_obj_s *self) { int err_code = EVENT_TRANSVR_EXCEP_INIT; int power_class = DEBUG_TRANSVR_INT_VAL; int hpmod_retry = 3; int lpower_config = 1; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; unsigned long hpmod_delay = 500; /* msec */ struct transvr_worker_s *task_p = NULL; /* Handle power mode for IOEXP */ power_class = __qsfp_get_power_cls(self, 0); switch (power_class) { case 1: /* Case: Low power mode (Class = 1) */ err_code = _taskfunc_qsfp_setup_power_mod(self, lpower_config); if (err_code < 0){ snprintf(err_msg, sizeof(err_msg), "Setup lpmod fail :%d", err_code); goto err_initfunc_qsfp_handle_power_mode; } return EVENT_TRANSVR_TASK_DONE; case 2: /* Case: High power mode (Class > 1) */ case 3: case 4: case 5: case 6: case 7: task_p = transvr_task_creat(self, taskfunc_qsfp_set_hpmod, taskfunc_post_handle_task_state, "transvr_init_qsfp"); if (!task_p) { snprintf(err_msg, sizeof(err_msg), "Setup lpmod fail :%d", err_code); goto err_initfunc_qsfp_handle_power_mode; } transvr_task_set_retry(task_p, hpmod_retry); transvr_task_set_delay(task_p, hpmod_delay); return EVENT_TRANSVR_TASK_WAIT; default: break; } snprintf(err_msg, sizeof(err_msg), "Exception case"); goto err_initfunc_qsfp_handle_power_mode; err_initfunc_qsfp_handle_power_mode: SWPS_INFO("%s: %s :%s \n", __func__, err_msg, self->swp_name); return EVENT_TRANSVR_INIT_FAIL; } int initfunc_qsfp28_handle_cdr(struct transvr_obj_s *self) { uint8_t DEFAULT_VAL_CDR = 0xff; int CDR_FUNC_EXISTED = 0x3; int show_err = 1; int err_val = EVENT_TRANSVR_TASK_FAIL; char *err_msg = DEBUG_TRANSVR_STR_VAL; char *func_str = "initfunc_qsfp28_handle_cdr"; err_val = __qsfp_get_cdr_present(self, 0); if ( (err_val < 0) || (err_val == DEBUG_TRANSVR_HEX_VAL) ) { err_msg = "detect cdr_present fail!"; goto err_taskfunc_qsfp_handle_cdr_1; } if (err_val == CDR_FUNC_EXISTED) { err_val = _common_set_uint8_attr(self, self->eeprom_map_p->addr_cdr, self->eeprom_map_p->addr_cdr, self->eeprom_map_p->offset_cdr, DEFAULT_VAL_CDR, &(self->cdr), func_str, show_err); if (err_val < 0) { err_msg = "set CDR fail!"; goto err_taskfunc_qsfp_handle_cdr_1; } } return EVENT_TRANSVR_TASK_DONE; err_taskfunc_qsfp_handle_cdr_1: SWPS_INFO("%s: %s :%d :%s\n", func_str, err_msg, err_val, self->swp_name); return EVENT_TRANSVR_INIT_FAIL; } /* ========== Object functions for Final State Machine ========== */ int is_plugged(struct transvr_obj_s *self){ int limit = 63; int present = DEBUG_TRANSVR_INT_VAL; char emsg[64] = DEBUG_TRANSVR_STR_VAL; struct ioexp_obj_s *ioexp_p = self->ioexp_obj_p; if (!ioexp_p) { snprintf(emsg, limit, "ioexp_p is null!"); goto err_is_plugged_1; } present = ioexp_p->get_present(ioexp_p, self->ioexp_virt_offset); switch (present){ case 0: return 1; case 1: return 0; case ERR_IOEXP_UNINIT: snprintf(emsg, limit, "ioexp_p not ready!"); goto err_is_plugged_1; default: if (ioexp_p->state == STATE_IOEXP_INIT){ snprintf(emsg, limit, "ioexp_p not ready!"); goto err_is_plugged_1; } break; } SWPS_INFO("%s: Exception case! :%d :%d\n", __func__, present, ioexp_p->state); return 0; err_is_plugged_1: SWPS_DEBUG("%s: %s\n", __func__, emsg); return 0; } static int detect_transvr_type(struct transvr_obj_s* self){ int type = TRANSVR_TYPE_ERROR; self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; type = i2c_smbus_read_byte_data(self->i2c_client_p, VAL_TRANSVR_COMID_OFFSET); /* Case: 1. Wait transceiver I2C module. * 2. Transceiver I2C module failure. * Note: 1. SFF allow maximum transceiver initial time is 2 second. So, there * are exist some case that we need to wait transceiver. * For these case, we keeps status on "TRANSVR_TYPE_UNPLUGGED", than * state machine will keep trace with it. * 2. There exist some I2C failure case we need to handle. Such as user * insert the failure transceiver, or any reason cause it abnormal. */ if (type < 0){ switch (type) { case -EIO: SWPS_DEBUG("%s: %s smbus return:-5 (I/O error)\n", __func__, self->swp_name); return TRANSVR_TYPE_UNPLUGGED; case -ENXIO: SWPS_DEBUG("%s: %s smbus return:-6 (No such device or address)\n", __func__, self->swp_name); return TRANSVR_TYPE_UNPLUGGED; default: break; } SWPS_INFO("%s: %s unexpected smbus return:%d \n", __func__, self->swp_name, type); return TRANSVR_TYPE_ERROR; } /* Identify valid transceiver type */ switch (type){ case TRANSVR_TYPE_SFP: case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: case TRANSVR_TYPE_QSFP_28: break; case TRANSVR_TYPE_UNKNOW_1: case TRANSVR_TYPE_UNKNOW_2: type = TRANSVR_TYPE_UNKNOW_2; break; default: SWPS_DEBUG("%s: unknow type:0x%02x \n", __func__, type); type = TRANSVR_TYPE_ERROR; break; } return type; } static int detect_transvr_state(struct transvr_obj_s *self, int result[2]){ /* [return] [result-0] [result-1] * 0 STATE_TRANSVR_CONNECTED TRANSVR_TYPE_FAKE * 0 STATE_TRANSVR_DISCONNECTED TRANSVR_TYPE_UNPLUGGED * 0 STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR * 0 STATE_TRANSVR_INIT / * 0 STATE_TRANSVR_SWAPPED * 0 STATE_TRANSVR_CONNECTED * ERR_TRNASVR_BE_ISOLATED STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR * ERR_TRANSVR_I2C_CRASH STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_ERROR * ERR_TRANSVR_UNEXCPT STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_UNKNOW_1/2 */ result[0] = STATE_TRANSVR_UNEXCEPTED; /* For return state */ result[1] = TRANSVR_TYPE_ERROR; /* For return type */ /* Case1: Fake type */ if (self->type == TRANSVR_TYPE_FAKE){ result[0] = STATE_TRANSVR_CONNECTED; result[1] = TRANSVR_TYPE_FAKE; return 0; } /* Case2: Transceiver unplugged */ if (!is_plugged(self)){ result[0] = STATE_TRANSVR_DISCONNECTED; result[1] = TRANSVR_TYPE_UNPLUGGED; return 0; } /* Case3: Transceiver be isolated */ if (self->state == STATE_TRANSVR_ISOLATED){ result[0] = STATE_TRANSVR_ISOLATED; result[1] = TRANSVR_TYPE_ERROR; return ERR_TRNASVR_BE_ISOLATED; } /* Case4: Transceiver plugged */ result[1] = detect_transvr_type(self); /* Case4.1: I2C topology crash * Note : There are some I2C issues cause by transceiver/cables. * We need to check topology status when user insert it. * But in this step, we can't not ensure this is the issues * port. So, it return the ERR_TRANSVR_I2C_CRASH, then upper * layer will diagnostic I2C topology. */ if (check_channel_tier_1() < 0) { SWPS_INFO("%s: %s detect I2C crash :%d\n", __func__, self->swp_name, self->state); result[0] = STATE_TRANSVR_UNEXCEPTED; result[1] = TRANSVR_TYPE_ERROR; return ERR_TRANSVR_I2C_CRASH; } /* Case4.2: System initial not ready, * Note : Sometime i2c channel or transceiver EEPROM will delay that will * cause system in inconsistent state between EEPROM and IOEXP. * In this case, SWP transceiver object keep state at LINK_DOWN * to wait system ready. * By the way, State Machine will handle these case. */ if (result[1] == TRANSVR_TYPE_UNPLUGGED){ result[0] = STATE_TRANSVR_DISCONNECTED; return 0; } /* Case4.3: Error transceiver type */ if (result[1] == TRANSVR_TYPE_ERROR){ result[0] = STATE_TRANSVR_ISOLATED; SWPS_INFO("%s: %s detect error type\n", __func__, self->swp_name); alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard!"); return ERR_TRNASVR_BE_ISOLATED; } /* Case3.3: Unknow transceiver type */ if ((result[1] == TRANSVR_TYPE_UNKNOW_1) || (result[1] == TRANSVR_TYPE_UNKNOW_2) ){ result[0] = STATE_TRANSVR_UNEXCEPTED; return ERR_TRANSVR_UNEXCPT; } /* Case3.4: During initial process */ if (self->state == STATE_TRANSVR_INIT){ result[0] = STATE_TRANSVR_INIT; return 0; } /* Case3.5: Transceiver be swapped */ if (self->type != result[1]){ result[0] = STATE_TRANSVR_SWAPPED; return 0; } /* Case3.6: Link up state */ result[0] = STATE_TRANSVR_CONNECTED; return 0; } int _sfp_detect_class_by_extend_comp(struct transvr_obj_s* self) { /* Reference: SFF-8024 (v3.8) */ int detect_val = _sfp_get_comp_extended(self); switch(detect_val) { case 0x00: /* Unspecified */ return TRANSVR_CLASS_UNSPECIFIED; case 0x01: /* 100G AOC (Active Optical Cable) or 25GAUI C2M */ case 0x18: /* 100G AOC or 25GAUI C2M AOC. */ return TRANSVR_CLASS_OPTICAL_25G_AOC; case 0x02: /* 100GBASE-SR4 or 25GBASE-SR */ return TRANSVR_CLASS_OPTICAL_25G_SR; case 0x03: /* 100GBASE-LR4 or 25GBASE-LR */ return TRANSVR_CLASS_OPTICAL_25G_LR; case 0x04: /* 100GBASE-ER4 or 25GBASE-ER */ return TRANSVR_CLASS_OPTICAL_25G_ER; case 0x08: /* 100G ACC (Active Copper Cable) or 25GAUI C2M ACC. */ case 0x0b: /* 100GBASE-CR4 or 25GBASE-CR CA-L */ case 0x0c: /* 25GBASE-CR CA-S */ case 0x0d: /* 25GBASE-CR CA-N */ case 0x19: /* 100G ACC or 25GAUI C2M ACC. */ return TRANSVR_CLASS_COPPER_L1_25G; default: break; } SWPS_INFO("%s: Unexcept value:0x%02x\n :%s", __func__, detect_val, self->swp_name); return TRANSVR_CLASS_ERROR; } int _sfp_detect_class_by_10_ethernet(struct transvr_obj_s* self) { /* Reference: SFF-8472 (v12.2) */ int detect_val = DEBUG_TRANSVR_INT_VAL; detect_val = _sfp_get_comp_10g_eth_comp(self); /* Case: Unspecified */ if (detect_val == 0x00) { return TRANSVR_CLASS_UNSPECIFIED; } /* Case: 10G Optical (x1) */ if ((detect_val & 0x10) == 0x10) { /* 00010000 : 10GBASE-SR */ return TRANSVR_CLASS_OPTICAL_10G_S_SR; } if ( ((detect_val & 0x20) == 0x20) || /* 00100000 : 10GBASE-LR */ ((detect_val & 0x40) == 0x40) ){ /* 01000000 : 10GBASE-LRM */ return TRANSVR_CLASS_OPTICAL_10G_S_LR; } if ((detect_val & 0x80) == 0x80) { /* 10000000 : 10GBASE-ER */ return TRANSVR_CLASS_OPTICAL_10G_S_ER; } /* Case: ERROR */ SWPS_INFO("%s: Unexcept value:0x%02x\n :%s", __func__, detect_val, self->swp_name); return TRANSVR_CLASS_ERROR; } int _sfp_detect_if_sp_by_br(struct transvr_obj_s* self) { int lower_bound_1g = 0x0b; int upper_bound_1g = 0x1A; int lower_bound_10g = 0x60; int upper_bound_10g = 0x75; int lower_bound_25g = 0xf0; int upper_bound_25g = 0xff; int notmal_br = DEBUG_TRANSVR_INT_VAL; notmal_br = (int)(self->br); /* updated by update_all() */ /* Check 25G */ if ((notmal_br >= lower_bound_25g) && (notmal_br <= upper_bound_25g) ) { return TRANSVR_CLASS_25G; } /* Check 10G */ if ((notmal_br >= lower_bound_10g) && (notmal_br <= upper_bound_10g) ) { return TRANSVR_CLASS_10G; } /* Check 1G */ if ((notmal_br >= lower_bound_1g) && (notmal_br <= upper_bound_1g) ) { return TRANSVR_CLASS_1G; } return TRANSVR_CLASS_UNSPECIFIED; } int _sfp_detect_class_by_1g_ethernet(struct transvr_obj_s* self) { /* Reference: SFF-8472 (v12.2) */ int detect_val = DEBUG_TRANSVR_INT_VAL; int speed_br = DEBUG_TRANSVR_INT_VAL; int speed_tmp = DEBUG_TRANSVR_INT_VAL; char err_str[64] = DEBUG_TRANSVR_STR_VAL; speed_br = _sfp_detect_if_sp_by_br(self); detect_val = _sfp_get_comp_1g_eth_comp(self); if (detect_val < 0) { snprintf(err_str, sizeof(err_str), "Detect abnormal value:%d", detect_val); goto err_p_sfp_detect_class_by_1g_ethernet; } /* Case: Unspecified */ if (detect_val == 0x00) { return TRANSVR_CLASS_UNSPECIFIED; } /* Case: 1G (x1) */ if ((detect_val & 0x01) == 0x01) { /* 00000001 : 1000BASE-SX */ speed_tmp = TRANSVR_CLASS_OPTICAL_1G_SX; goto ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g; } if ((detect_val & 0x02) == 0x02) { /* 00000010 : 1000BASE-LX *3 */ speed_tmp = TRANSVR_CLASS_OPTICAL_1G_LX; goto ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g; } if ((detect_val & 0x04) == 0x04) { /* 00000100 : 1000BASE-CX */ speed_tmp = TRANSVR_CLASS_COPPER_L1_1G; goto ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g; } /* Case: 1000 Base-T (x1) */ if ((detect_val & 0x08) == 0x08) { /* 00001000 : 1000BASE-T */ return TRANSVR_CLASS_BASE_T_1000; } /* Case: 100 Base */ if ( ((detect_val & 0x10) == 0x10) || /* 00010000 : 100BASE-LX/LX10 */ ((detect_val & 0x20) == 0x20) || /* 00100000 : 100BASE-FX */ ((detect_val & 0x40) == 0x40) || /* 01000000 : BASE-BX10 *3 */ ((detect_val & 0x80) == 0x80) ){ /* 10000000 : BASE-PX *3 */ return TRANSVR_CLASS_OPTICAL_100; } /* Case: ERROR */ snprintf(err_str, sizeof(err_str), "Case:ERROR, value:%d", detect_val); goto err_p_sfp_detect_class_by_1g_ethernet; ok_sfp_detect_class_by_1g_ethernet_4_check_br_10g: switch (speed_br) { case TRANSVR_CLASS_UNSPECIFIED: case TRANSVR_CLASS_1G: return speed_tmp; case TRANSVR_CLASS_10G: goto ok_sfp_detect_class_by_1g_ethernet_4_transfer_10G; } ok_sfp_detect_class_by_1g_ethernet_4_transfer_10G: switch (speed_tmp) { case TRANSVR_CLASS_OPTICAL_1G_SX: return TRANSVR_CLASS_OPTICAL_10G_S_SR; case TRANSVR_CLASS_OPTICAL_1G_LX: return TRANSVR_CLASS_OPTICAL_10G_S_LR; case TRANSVR_CLASS_COPPER_L1_1G: return TRANSVR_CLASS_COPPER_L1_10G; default: break; } snprintf(err_str, sizeof(err_str), "transfer_1to10 fail, speed:%d", speed_tmp); goto err_p_sfp_detect_class_by_1g_ethernet; err_p_sfp_detect_class_by_1g_ethernet: SWPS_INFO("%s: %s :%s", __func__, err_str, self->swp_name); return TRANSVR_CLASS_ERROR; } int _sfp_detect_class_by_feature(struct transvr_obj_s* self) { /* Reference: SFF-8024 (v3.8) */ int is_active = 0; int conn_val = DEBUG_TRANSVR_INT_VAL; int check_val = DEBUG_TRANSVR_INT_VAL; int wave_len = DEBUG_TRANSVR_INT_VAL; int speed_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; speed_val = _sfp_detect_if_sp_by_br(self); conn_val = _sfp_get_connector_type(self); switch(conn_val) { case 0x00: /* Unspecified */ goto ok_sfp_detect_class_by_feature_4_check_active_passive; case 0x07: /* LC (Lucent Connector) */ case 0x0b: /* Optical Pigtail */ case 0x0c: /* MPO 1x12 */ case 0x0d: /* MPO 2x16 */ /* * ToDo: Need verify Optical Pigtail */ goto ok_sfp_detect_class_by_feature_4_optiocal; case 0x21: /* Copper pigtail */ /* * ToDo: Need check ACC use case */ goto ok_sfp_detect_class_by_feature_4_check_active_passive; case 0x23: /* No separable connector */ /* * ToDo: Standard not clear, not all transceiver vendor * have the same defined */ goto ok_sfp_detect_class_by_feature_4_check_active_passive; default: break; } goto ok_sfp_detect_class_by_feature_4_unknow; ok_sfp_detect_class_by_feature_4_check_active_passive: check_val = _sfp_get_cable_tech(self); switch(check_val) { case 0x00: /* Unspecified */ goto ok_sfp_detect_class_by_feature_4_unknow; case 0x04: /* Passive */ goto ok_sfp_detect_class_by_feature_4_copper; case 0x08: /* Active */ is_active = 1; goto ok_sfp_detect_class_by_feature_4_aoc; default: snprintf(err_msg, sizeof(err_msg), "_sfp_get_cable_tech return Non define value:%d", check_val); break; } goto err_sfp_detect_class_by_feature_1; ok_sfp_detect_class_by_feature_4_optiocal: wave_len = _common_count_wavelength(self, self->wavelength[0], self->wavelength[1]); switch(speed_val) { case TRANSVR_CLASS_25G: switch (wave_len) { case VAL_OPTICAL_WAVELENGTH_SR: return TRANSVR_CLASS_OPTICAL_25G_SR; case VAL_OPTICAL_WAVELENGTH_LR: return TRANSVR_CLASS_OPTICAL_25G_LR; case VAL_OPTICAL_WAVELENGTH_ER: return TRANSVR_CLASS_OPTICAL_25G_ER; default: break; } return TRANSVR_CLASS_OPTICAL_25G; case TRANSVR_CLASS_10G: switch (wave_len) { case VAL_OPTICAL_WAVELENGTH_SR: return TRANSVR_CLASS_OPTICAL_10G_S_SR; case VAL_OPTICAL_WAVELENGTH_LR: return TRANSVR_CLASS_OPTICAL_10G_S_LR; case VAL_OPTICAL_WAVELENGTH_ER: return TRANSVR_CLASS_OPTICAL_10G_S_ER; default: break; } return TRANSVR_CLASS_OPTICAL_10G; case TRANSVR_CLASS_1G: switch (wave_len) { case VAL_OPTICAL_WAVELENGTH_SR: return TRANSVR_CLASS_OPTICAL_1G_SX; case VAL_OPTICAL_WAVELENGTH_LR: return TRANSVR_CLASS_OPTICAL_1G_LX; case VAL_OPTICAL_WAVELENGTH_ER: return TRANSVR_CLASS_OPTICAL_1G_EX; default: break; } return TRANSVR_CLASS_OPTICAL_1G; default: return TRANSVR_CLASS_OPTICAL; } ok_sfp_detect_class_by_feature_4_aoc: switch(speed_val) { case TRANSVR_CLASS_25G: return TRANSVR_CLASS_OPTICAL_25G_AOC; case TRANSVR_CLASS_10G: return TRANSVR_CLASS_OPTICAL_10G_S_AOC; case TRANSVR_CLASS_1G: return TRANSVR_CLASS_OPTICAL_1G_AOC; default: break; } goto ok_sfp_detect_class_by_feature_4_unknow; ok_sfp_detect_class_by_feature_4_copper: switch(speed_val) { case TRANSVR_CLASS_25G: return TRANSVR_CLASS_COPPER_L1_25G; case TRANSVR_CLASS_10G: return TRANSVR_CLASS_COPPER_L1_10G; case TRANSVR_CLASS_1G: return TRANSVR_CLASS_COPPER_L1_1G; default: return TRANSVR_CLASS_COPPER; } ok_sfp_detect_class_by_feature_4_unknow: return TRANSVR_CLASS_UNSPECIFIED; err_sfp_detect_class_by_feature_1: SWPS_INFO("%s: %s\n :%s", __func__, err_msg, self->swp_name); return TRANSVR_CLASS_ERROR; } int sft_detect_transvr_class(struct transvr_obj_s* self) { int detect_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; /* Check Extended Compliance */ detect_val = _sfp_detect_class_by_extend_comp(self); switch(detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL_25G_AOC: case TRANSVR_CLASS_OPTICAL_25G_SR: case TRANSVR_CLASS_OPTICAL_25G_LR: case TRANSVR_CLASS_OPTICAL_25G_ER: case TRANSVR_CLASS_COPPER_L1_25G: return detect_val; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined extend_comp:%d", detect_val); goto err_sft_detect_transceiver_class_1; } /* Check 10G Compliance */ detect_val = _sfp_detect_class_by_10_ethernet(self); switch(detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL_10G_S_SR: case TRANSVR_CLASS_OPTICAL_10G_S_LR: case TRANSVR_CLASS_OPTICAL_10G_S_ER: return detect_val; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined 10G_eth:%d", detect_val); goto err_sft_detect_transceiver_class_1; } /* Check 1G Compliance */ detect_val = _sfp_detect_class_by_1g_ethernet(self); switch(detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL_1G_SX: case TRANSVR_CLASS_OPTICAL_1G_LX: case TRANSVR_CLASS_COPPER_L1_1G: case TRANSVR_CLASS_BASE_T_1000: case TRANSVR_CLASS_OPTICAL_100: /* * ToDo: Need Check 0.1G */ case TRANSVR_CLASS_OPTICAL_10G_S_SR: case TRANSVR_CLASS_OPTICAL_10G_S_LR: case TRANSVR_CLASS_COPPER_L1_10G: /* Transfer speed case * => Example: Raycom 10G DAC */ return detect_val; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined 1G_eth:%d", detect_val); goto err_sft_detect_transceiver_class_1; } /* Check by connector, br, wavelength */ detect_val = _sfp_detect_class_by_feature(self); switch(detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL: case TRANSVR_CLASS_OPTICAL_1G: case TRANSVR_CLASS_OPTICAL_1G_SX: case TRANSVR_CLASS_OPTICAL_1G_LX: case TRANSVR_CLASS_OPTICAL_1G_EX: case TRANSVR_CLASS_OPTICAL_1G_AOC: case TRANSVR_CLASS_OPTICAL_10G: case TRANSVR_CLASS_OPTICAL_10G_S_SR: case TRANSVR_CLASS_OPTICAL_10G_S_LR: case TRANSVR_CLASS_OPTICAL_10G_S_ER: case TRANSVR_CLASS_OPTICAL_10G_S_AOC: case TRANSVR_CLASS_OPTICAL_25G: case TRANSVR_CLASS_OPTICAL_25G_SR: case TRANSVR_CLASS_OPTICAL_25G_LR: case TRANSVR_CLASS_OPTICAL_25G_ER: case TRANSVR_CLASS_OPTICAL_25G_AOC: case TRANSVR_CLASS_COPPER: case TRANSVR_CLASS_COPPER_L1_1G: case TRANSVR_CLASS_COPPER_L1_10G: case TRANSVR_CLASS_COPPER_L1_25G: return detect_val; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined get_connector:%d", detect_val); goto err_sft_detect_transceiver_class_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_sft_detect_transceiver_class_1; err_sft_detect_transceiver_class_1: SWPS_INFO("%s: %s :%s\n", __func__, err_msg, self->swp_name); return TRANSVR_CLASS_ERROR; } int _sfp_set_trident2_if_type(struct transvr_obj_s* self, int transvr_cls, char *result){ int lmax = 8; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; switch(transvr_cls) { case TRANSVR_CLASS_ERROR: case TRANSVR_CLASS_UNSPECIFIED: break; /* 25G OPTICAL */ case TRANSVR_CLASS_OPTICAL_25G_AOC: case TRANSVR_CLASS_OPTICAL_25G_SR: case TRANSVR_CLASS_OPTICAL_25G_LR: case TRANSVR_CLASS_OPTICAL_25G_ER: case TRANSVR_CLASS_OPTICAL_25G: return snprintf(result, lmax, TRANSVR_IF_SFI); /* 25G COPPER */ case TRANSVR_CLASS_COPPER_L1_25G: return snprintf(result, lmax, TRANSVR_IF_SFI); /* 10G OPTICAL */ case TRANSVR_CLASS_OPTICAL_10G_S_AOC: case TRANSVR_CLASS_OPTICAL_10G_S_SR: case TRANSVR_CLASS_OPTICAL_10G_S_LR: case TRANSVR_CLASS_OPTICAL_10G_S_ER: case TRANSVR_CLASS_OPTICAL_10G: return snprintf(result, lmax, TRANSVR_IF_SFI); /* 10G COPPER */ case TRANSVR_CLASS_COPPER_L1_10G: return snprintf(result, lmax, TRANSVR_IF_SFI); /* 1G OPTICAL */ case TRANSVR_CLASS_OPTICAL_1G_AOC: case TRANSVR_CLASS_OPTICAL_1G_SX: case TRANSVR_CLASS_OPTICAL_1G_LX: case TRANSVR_CLASS_OPTICAL_1G_EX: case TRANSVR_CLASS_OPTICAL_1G: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); /* 1G COPPER */ case TRANSVR_CLASS_COPPER_L1_1G: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); /* 1G BASE_T */ case TRANSVR_CLASS_BASE_T_1000: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); /* 100 Base */ case TRANSVR_CLASS_OPTICAL_100: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); default: snprintf(err_msg, sizeof(err_msg), "Detect undefined value:%d", transvr_cls); goto err_sfp_set_trident2_if_type_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_sfp_set_trident2_if_type_1; err_sfp_set_trident2_if_type_1: snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); SWPS_INFO("%s: %s :%s\n", __func__, err_msg, self->swp_name); return ERR_TRANSVR_ABNORMAL; } int _sfp_set_tomahawk_if_type(struct transvr_obj_s* self, int transvr_cls, char *result) { int lmax = 8; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; switch(transvr_cls) { case TRANSVR_CLASS_ERROR: case TRANSVR_CLASS_UNSPECIFIED: break; /* 25G OPTICAL */ case TRANSVR_CLASS_OPTICAL_25G_AOC: case TRANSVR_CLASS_OPTICAL_25G_SR: case TRANSVR_CLASS_OPTICAL_25G_LR: case TRANSVR_CLASS_OPTICAL_25G_ER: case TRANSVR_CLASS_OPTICAL_25G: return snprintf(result, lmax, TRANSVR_IF_SR); /* 25G COPPER */ case TRANSVR_CLASS_COPPER_L1_25G: return snprintf(result, lmax, TRANSVR_IF_KR); /* 10G OPTICAL */ case TRANSVR_CLASS_OPTICAL_10G_S_AOC: case TRANSVR_CLASS_OPTICAL_10G_S_SR: case TRANSVR_CLASS_OPTICAL_10G_S_LR: case TRANSVR_CLASS_OPTICAL_10G_S_ER: case TRANSVR_CLASS_OPTICAL_10G: return snprintf(result, lmax, TRANSVR_IF_SFI); /* 10G COPPER */ case TRANSVR_CLASS_COPPER_L1_10G: return snprintf(result, lmax, TRANSVR_IF_SFI); /* 1G OPTICAL */ case TRANSVR_CLASS_OPTICAL_1G_AOC: case TRANSVR_CLASS_OPTICAL_1G_SX: case TRANSVR_CLASS_OPTICAL_1G_LX: case TRANSVR_CLASS_OPTICAL_1G_EX: case TRANSVR_CLASS_OPTICAL_1G: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); /* 1G COPPER */ case TRANSVR_CLASS_COPPER_L1_1G: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); /* 1G BASE_T */ case TRANSVR_CLASS_BASE_T_1000: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); /* 100 Base */ case TRANSVR_CLASS_OPTICAL_100: return snprintf(result, lmax, TRANSVR_IF_IF_GMII); default: snprintf(err_msg, sizeof(err_msg), "Detect undefined value:%d", transvr_cls); goto err_sfp_set_tomahawk_if_type_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_sfp_set_tomahawk_if_type_1; err_sfp_set_tomahawk_if_type_1: snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); SWPS_INFO("%s: %s\n :%s", __func__, err_msg, self->swp_name); return ERR_TRANSVR_ABNORMAL; } int _sfp_detect_if_type(struct transvr_obj_s* self, char *result){ int lmax = 8; int detect_cls = DEBUG_TRANSVR_INT_VAL; detect_cls = sft_detect_transvr_class(self); switch (self->chipset_type) { case BCM_CHIP_TYPE_TRIDENT_2: return _sfp_set_trident2_if_type(self, detect_cls, result); case BCM_CHIP_TYPE_TOMAHAWK: return _sfp_set_tomahawk_if_type(self, detect_cls, result); default: SWPS_INFO("%s: non-defined chipset_type:%d :%s\n", __func__, self->chipset_type, self->swp_name); break; } snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); return ERR_TRANSVR_ABNORMAL; } int sfp_get_if_type(struct transvr_obj_s *self, char *buf_p){ int lmax = 16; char tmp_result[16] = DEBUG_TRANSVR_STR_VAL; if (self->state != STATE_TRANSVR_CONNECTED) { return snprintf(buf_p, lmax, "%d\n", self->state); } if (_sfp_detect_if_type(self, tmp_result) < 0) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL); } return snprintf(buf_p, lmax, "%s\n", tmp_result); } int _sfp_detect_if_speed(struct transvr_obj_s* self, char *result){ int lmax = 16; int detect_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; detect_val = sft_detect_transvr_class(self); switch(detect_val) { case TRANSVR_CLASS_ERROR: case TRANSVR_CLASS_UNSPECIFIED: break; /* 25G OPTICAL */ case TRANSVR_CLASS_OPTICAL_25G_AOC: case TRANSVR_CLASS_OPTICAL_25G_SR: case TRANSVR_CLASS_OPTICAL_25G_LR: case TRANSVR_CLASS_OPTICAL_25G_ER: case TRANSVR_CLASS_OPTICAL_25G: return snprintf(result, lmax, TRANSVR_IF_SP_25G); /* 25G COPPER */ case TRANSVR_CLASS_COPPER_L1_25G: return snprintf(result, lmax, TRANSVR_IF_SP_25G); /* 10G OPTICAL */ case TRANSVR_CLASS_OPTICAL_10G_S_AOC: case TRANSVR_CLASS_OPTICAL_10G_S_SR: case TRANSVR_CLASS_OPTICAL_10G_S_LR: case TRANSVR_CLASS_OPTICAL_10G_S_ER: case TRANSVR_CLASS_OPTICAL_10G: return snprintf(result, lmax, TRANSVR_IF_SP_10G); /* 10G COPPER */ case TRANSVR_CLASS_COPPER_L1_10G: return snprintf(result, lmax, TRANSVR_IF_SP_10G); /* 1G OPTICAL */ case TRANSVR_CLASS_OPTICAL_1G_AOC: case TRANSVR_CLASS_OPTICAL_1G_SX: case TRANSVR_CLASS_OPTICAL_1G_LX: case TRANSVR_CLASS_OPTICAL_1G_EX: case TRANSVR_CLASS_OPTICAL_1G: return snprintf(result, lmax, TRANSVR_IF_SP_1G); /* 1G COPPER */ case TRANSVR_CLASS_COPPER_L1_1G: return snprintf(result, lmax, TRANSVR_IF_SP_1G); /* 1G BASE_T */ case TRANSVR_CLASS_BASE_T_1000: return snprintf(result, lmax, TRANSVR_IF_SP_1G); /* 100 Base */ case TRANSVR_CLASS_OPTICAL_100: return snprintf(result, lmax, TRANSVR_IF_SP_100); default: snprintf(err_msg, sizeof(err_msg), "Detect undefined value:%d", detect_val); goto err_sfp_detect_if_speed_1; } /* Check by BR */ detect_val = _sfp_detect_if_sp_by_br(self); switch (detect_val) { case TRANSVR_CLASS_25G: return snprintf(result, lmax, TRANSVR_IF_SP_25G); case TRANSVR_CLASS_10G: return snprintf(result, lmax, TRANSVR_IF_SP_10G); case TRANSVR_CLASS_1G: return snprintf(result, lmax, TRANSVR_IF_SP_1G); default: break; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_sfp_detect_if_speed_1; err_sfp_detect_if_speed_1: snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); SWPS_INFO("%s %s\n :%s", __func__, err_msg, self->swp_name); return ERR_TRANSVR_ABNORMAL; } int sfp_get_if_speed(struct transvr_obj_s *self, char *buf_p){ int lmax = 16; char tmp_result[16] = DEBUG_TRANSVR_STR_VAL; if (self->state != STATE_TRANSVR_CONNECTED) { return snprintf(buf_p, lmax, "%d\n", self->state); } if (_sfp_detect_if_speed(self, tmp_result) < 0) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL); } return snprintf(buf_p, lmax, "%s\n", tmp_result); } int _qsfp_detect_class_by_extend_comp(struct transvr_obj_s* self) { /* Reference: SFF-8024 (v3.8) */ int detect_val = DEBUG_TRANSVR_INT_VAL; detect_val = _qsfp_get_comp_extended(self); switch(detect_val) { case 0x00: /* Unspecified */ return TRANSVR_CLASS_UNSPECIFIED; case 0x01: /* 100G AOC (Active Optical Cable) or 25GAUI C2M */ case 0x18: /* 100G AOC or 25GAUI C2M AOC. */ return TRANSVR_CLASS_OPTICAL_100G_AOC; case 0x06: /* 100G CWDM4 */ case 0x09: /* Obsolete (assigned before 100G CWDM4 MSA required FEC) */ case 0x17: /* 100G CLR4 */ case 0x1A: /* 100GE-DWDM2 */ return TRANSVR_CLASS_OPTICAL_100G; case 0x02: /* 100GBASE-SR4 or 25GBASE-SR */ return TRANSVR_CLASS_OPTICAL_100G_SR4; case 0x03: /* 100GBASE-LR4 or 25GBASE-LR */ return TRANSVR_CLASS_OPTICAL_100G_LR4; case 0x04: /* 100GBASE-ER4 or 25GBASE-ER */ return TRANSVR_CLASS_OPTICAL_100G_ER4; case 0x07: /* 100G PSM4 Parallel SMF */ return TRANSVR_CLASS_OPTICAL_100G_PSM4; case 0x12: /* 40G PSM4 Parallel SMF */ return TRANSVR_CLASS_OPTICAL_40G; case 0x11: /* 4 x 10GBASE-SR */ return TRANSVR_CLASS_OPTICAL_40G_SR4; case 0x10: /* 40GBASE-ER4 */ return TRANSVR_CLASS_OPTICAL_40G_ER4; case 0x08: /* 100G ACC (Active Copper Cable) or 25GAUI C2M ACC. */ case 0x0b: /* 100GBASE-CR4 or 25GBASE-CR CA-L */ case 0x19: /* 100G ACC or 25GAUI C2M ACC. */ return TRANSVR_CLASS_COPPER_L4_100G; default: break; } SWPS_INFO("%s: Unexcept value:0x%02x\n :%s", __func__, detect_val, self->swp_name); return TRANSVR_CLASS_ERROR; } int _qsfp_detect_class_by_10_40_100_ethernet(struct transvr_obj_s* self) { /* Reference: SFF-8472 (v12.2) */ int detect_val = DEBUG_TRANSVR_INT_VAL; detect_val = _qsfp_get_comp_10_40_100_ethernet(self); /* Case: Unspecified */ if (detect_val == 0x00) { return TRANSVR_CLASS_UNSPECIFIED; } /* Case: 40G Optical */ if ((detect_val & 0x01) == 0x01) { /* 00000001 : 40G Active Cable (XLPPI) */ return TRANSVR_CLASS_OPTICAL_40G_AOC; } if ((detect_val & 0x04) == 0x04) { /* 00000100 : 40GBASE-SR4 */ return TRANSVR_CLASS_OPTICAL_40G_SR4; } if ( (detect_val & 0x02) == 0x02) { /* 00000010 : 40GBASE-LR4 */ return TRANSVR_CLASS_OPTICAL_40G_LR4; } if ( (detect_val & 0x08) == 0x08) { /* 00001000 : 40GBASE-CR4 */ return TRANSVR_CLASS_COPPER_L4_40G; } /* Case: 10G Optical */ if ( (detect_val & 0x10) == 0x10) { /* 00010000 : 10GBASE-SR */ return TRANSVR_CLASS_OPTICAL_10G_Q_SR; } if ( ((detect_val & 0x20) == 0x20) || /* 00100000 : 10GBASE-LR */ ((detect_val & 0x40) == 0x40) ){ /* 01000000 : 10GBASE-LRM */ return TRANSVR_CLASS_OPTICAL_10G_Q_LR; } /* Case: Extend Compliance */ if ( ((detect_val & 0x80) == 0x80) ){ /* 10000000 : Use Extend Compliance */ return TRANSVR_CLASS_EXTEND_COMP; } /* Case: ERROR */ SWPS_INFO("%s: Unexcept value:0x%02x\n :%s", __func__, detect_val, self->swp_name); return TRANSVR_CLASS_ERROR; } int _qsfp_detect_if_sp_by_br(struct transvr_obj_s* self) { int lower_bound_10g = 0x10; int upper_bound_10g = 0x25; int lower_bound_40g = 0x60; int upper_bound_40g = 0x75; int lower_bound_100g = 0x60; int upper_bound_100g = 0x75; int used_extend_br = 0xff; int notmal_br = DEBUG_TRANSVR_INT_VAL; int extend_br = DEBUG_TRANSVR_INT_VAL; notmal_br = (int)(self->br); /* updated by update_all() */ /* Check 40G */ if ((notmal_br >= lower_bound_40g) && (notmal_br <= upper_bound_40g) ) { return TRANSVR_CLASS_40G; } /* Check 100G */ if (notmal_br == used_extend_br) { extend_br = (int)(self->extbr); /* updated by update_all() */ if ((extend_br >= lower_bound_100g) && (extend_br <= upper_bound_100g) ) { return TRANSVR_CLASS_100G; } } /* Check 10G */ if ((notmal_br >= lower_bound_10g) && (notmal_br <= upper_bound_10g) ) { return TRANSVR_CLASS_10G; } return TRANSVR_CLASS_UNSPECIFIED; } int _qsfp_detect_class_by_feature(struct transvr_obj_s* self) { /* Reference: SFF-8024 (v3.8) */ int conn_val = DEBUG_TRANSVR_INT_VAL; int wave_len = DEBUG_TRANSVR_INT_VAL; int speed_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; speed_val = _qsfp_detect_if_sp_by_br(self); conn_val = _qsfp_get_connector_type(self); switch(conn_val) { case 0x00: /* Unspecified */ return TRANSVR_CLASS_UNSPECIFIED; case 0x07: /* LC (Lucent Connector) */ case 0x0b: /* Optical Pigtail */ case 0x0c: /* MPO 1x12 (Multifiber Parallel Optic) */ case 0x0d: /* MPO 2x16 */ goto ok_qsfp_detect_class_by_feature_4_optiocal; case 0x21: /* Copper pigtail */ goto ok_qsfp_detect_class_by_feature_4_copper; case 0x23: /* No separable connector */ if ((_qsfp_get_comp_fc_link_length(self) > 0) || (_qsfp_get_comp_fc_trans_tech(self) > 0) || (_qsfp_get_comp_fc_trans_media(self) > 0) || (_qsfp_get_comp_fc_speed(self) > 0) ) { goto ok_qsfp_detect_class_by_feature_4_aoc; } goto ok_qsfp_detect_class_by_feature_4_copper; default: snprintf(err_msg, sizeof(err_msg), "_qsfp_get_connector_type return Non define value:%d", conn_val); goto err_qsfp_detect_class_by_feature_1; } return TRANSVR_CLASS_UNSPECIFIED; ok_qsfp_detect_class_by_feature_4_optiocal: wave_len = _common_count_wavelength(self, self->wavelength[0], self->wavelength[1]); switch(speed_val) { case TRANSVR_CLASS_100G: switch (wave_len) { case VAL_OPTICAL_WAVELENGTH_SR: return TRANSVR_CLASS_OPTICAL_100G_SR4; case VAL_OPTICAL_WAVELENGTH_LR: return TRANSVR_CLASS_OPTICAL_100G_LR4; case VAL_OPTICAL_WAVELENGTH_ER: return TRANSVR_CLASS_OPTICAL_100G_ER4; default: break; } return TRANSVR_CLASS_OPTICAL_100G; case TRANSVR_CLASS_40G: switch (wave_len) { case VAL_OPTICAL_WAVELENGTH_SR: return TRANSVR_CLASS_OPTICAL_40G_SR4; case VAL_OPTICAL_WAVELENGTH_LR: return TRANSVR_CLASS_OPTICAL_40G_LR4; case VAL_OPTICAL_WAVELENGTH_ER: return TRANSVR_CLASS_OPTICAL_40G_ER4; default: break; } return TRANSVR_CLASS_OPTICAL_40G; case TRANSVR_CLASS_10G: switch (wave_len) { case VAL_OPTICAL_WAVELENGTH_SR: return TRANSVR_CLASS_OPTICAL_10G_Q_SR; case VAL_OPTICAL_WAVELENGTH_LR: return TRANSVR_CLASS_OPTICAL_10G_Q_LR; case VAL_OPTICAL_WAVELENGTH_ER: return TRANSVR_CLASS_OPTICAL_10G_Q_ER; default: break; } return TRANSVR_CLASS_OPTICAL_10G; default: return TRANSVR_CLASS_OPTICAL; } ok_qsfp_detect_class_by_feature_4_aoc: switch(speed_val) { case TRANSVR_CLASS_100G: return TRANSVR_CLASS_OPTICAL_100G_AOC; case TRANSVR_CLASS_40G: return TRANSVR_CLASS_OPTICAL_40G_AOC; case TRANSVR_CLASS_10G: return TRANSVR_CLASS_OPTICAL_10G_Q_AOC; default: return TRANSVR_CLASS_OPTICAL; } ok_qsfp_detect_class_by_feature_4_copper: switch(speed_val) { case TRANSVR_CLASS_100G: return TRANSVR_CLASS_COPPER_L4_100G; case TRANSVR_CLASS_40G: return TRANSVR_CLASS_COPPER_L4_40G; case TRANSVR_CLASS_10G: return TRANSVR_CLASS_COPPER_L4_10G; default: return TRANSVR_CLASS_COPPER; } err_qsfp_detect_class_by_feature_1: SWPS_INFO("%s: %s\n :%s", __func__, err_msg, self->swp_name); return TRANSVR_CLASS_ERROR; } int qsft_detect_transvr_class(struct transvr_obj_s* self) { int detect_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; /* Check Extended Compliance */ detect_val = _qsfp_detect_class_by_extend_comp(self); switch (detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL_100G: case TRANSVR_CLASS_OPTICAL_100G_AOC: case TRANSVR_CLASS_OPTICAL_100G_SR4: case TRANSVR_CLASS_OPTICAL_100G_LR4: case TRANSVR_CLASS_OPTICAL_100G_ER4: case TRANSVR_CLASS_OPTICAL_100G_PSM4: case TRANSVR_CLASS_OPTICAL_40G: case TRANSVR_CLASS_OPTICAL_40G_AOC: case TRANSVR_CLASS_OPTICAL_40G_SR4: case TRANSVR_CLASS_OPTICAL_40G_LR4: case TRANSVR_CLASS_OPTICAL_40G_ER4: case TRANSVR_CLASS_COPPER_L4_100G: return detect_val; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined extend_comp:%d", detect_val); goto err_qsft_detect_transvr_class_1; } /* Check 10/40G/100G Ethernet Compliance */ detect_val = _qsfp_detect_class_by_10_40_100_ethernet(self); switch(detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL_40G_AOC: case TRANSVR_CLASS_OPTICAL_40G_SR4: case TRANSVR_CLASS_OPTICAL_40G_LR4: case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_COPPER_L4_40G: return detect_val; case TRANSVR_CLASS_EXTEND_COMP: /* Format incorrect case (We already checked the Extend * Compliance is 0 */ snprintf(err_msg, sizeof(err_msg), "Transceiver format incorrect"); goto err_qsft_detect_transvr_class_1; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined 10/40/100:%d", detect_val); goto err_qsft_detect_transvr_class_1; } /* Check by Connector type, BR and wavelength */ detect_val = _qsfp_detect_class_by_feature(self); switch (detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_OPTICAL_100G_ER4: case TRANSVR_CLASS_OPTICAL_100G_LR4: case TRANSVR_CLASS_OPTICAL_100G_SR4: case TRANSVR_CLASS_OPTICAL_100G_AOC: case TRANSVR_CLASS_OPTICAL_100G: case TRANSVR_CLASS_OPTICAL_40G_ER4: case TRANSVR_CLASS_OPTICAL_40G_LR4: case TRANSVR_CLASS_OPTICAL_40G_SR4: case TRANSVR_CLASS_OPTICAL_40G_AOC: case TRANSVR_CLASS_OPTICAL_40G: case TRANSVR_CLASS_OPTICAL_10G_Q_ER: case TRANSVR_CLASS_OPTICAL_10G_Q_LR: case TRANSVR_CLASS_OPTICAL_10G_Q_SR: case TRANSVR_CLASS_OPTICAL_10G_Q_AOC: case TRANSVR_CLASS_OPTICAL_10G: case TRANSVR_CLASS_OPTICAL: case TRANSVR_CLASS_COPPER_L4_100G: case TRANSVR_CLASS_COPPER_L4_40G: case TRANSVR_CLASS_COPPER_L4_10G: case TRANSVR_CLASS_COPPER: return detect_val; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined connector:%d", detect_val); goto err_qsft_detect_transvr_class_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_qsft_detect_transvr_class_1; err_qsft_detect_transvr_class_1: SWPS_INFO("%s: %s\n :%s", __func__, err_msg, self->swp_name); return TRANSVR_CLASS_ERROR; } int _qsfp_set_trident2_if_type(struct transvr_obj_s* self, int transvr_cls, char *result){ int lmax = 8; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; switch (transvr_cls) { case TRANSVR_CLASS_UNSPECIFIED: case TRANSVR_CLASS_ERROR: break; /* 100G Optical */ case TRANSVR_CLASS_OPTICAL_100G: case TRANSVR_CLASS_OPTICAL_100G_AOC: case TRANSVR_CLASS_OPTICAL_100G_SR4: case TRANSVR_CLASS_OPTICAL_100G_LR4: case TRANSVR_CLASS_OPTICAL_100G_ER4: case TRANSVR_CLASS_OPTICAL_100G_PSM4: return snprintf(result, lmax, TRANSVR_IF_SR4); /* 100G Copper */ case TRANSVR_CLASS_COPPER_L4_100G: return snprintf(result, lmax, TRANSVR_IF_KR4); /* 40G Optical */ case TRANSVR_CLASS_OPTICAL_40G: case TRANSVR_CLASS_OPTICAL_40G_AOC: case TRANSVR_CLASS_OPTICAL_40G_SR4: case TRANSVR_CLASS_OPTICAL_40G_LR4: case TRANSVR_CLASS_OPTICAL_40G_ER4: return snprintf(result, lmax, TRANSVR_IF_IF_XGMII); /* 40G Copper */ case TRANSVR_CLASS_COPPER_L4_40G: return snprintf(result, lmax, TRANSVR_IF_IF_XGMII); /* 10G Optical */ case TRANSVR_CLASS_OPTICAL_10G: case TRANSVR_CLASS_OPTICAL_10G_Q_AOC: case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: LR4 or LR */ case TRANSVR_CLASS_OPTICAL_10G_Q_ER: /* Need Check: ER4 or ER */ return snprintf(result, lmax, TRANSVR_IF_IF_XGMII); /* Optical */ case TRANSVR_CLASS_OPTICAL: return snprintf(result, lmax, TRANSVR_IF_IF_XGMII); /* Copper */ case TRANSVR_CLASS_COPPER: return snprintf(result, lmax, TRANSVR_IF_IF_XGMII); default: snprintf(err_msg, sizeof(err_msg), "Detect undefined value:%d", transvr_cls); goto err_qsfp_set_trident2_if_type_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_qsfp_set_trident2_if_type_1; err_qsfp_set_trident2_if_type_1: snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); SWPS_INFO("%s: %s\n :%s", __func__, err_msg, self->swp_name); return ERR_TRANSVR_ABNORMAL; } int _qsfp_set_tomahawk_if_type(struct transvr_obj_s* self, int transvr_cls, char *result){ int lmax = 8; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; switch (transvr_cls) { case TRANSVR_CLASS_UNSPECIFIED: case TRANSVR_CLASS_ERROR: break; /* 100G Optical */ case TRANSVR_CLASS_OPTICAL_100G: case TRANSVR_CLASS_OPTICAL_100G_AOC: case TRANSVR_CLASS_OPTICAL_100G_SR4: case TRANSVR_CLASS_OPTICAL_100G_LR4: case TRANSVR_CLASS_OPTICAL_100G_ER4: case TRANSVR_CLASS_OPTICAL_100G_PSM4: return snprintf(result, lmax, TRANSVR_IF_SR4); /* 100G Copper */ case TRANSVR_CLASS_COPPER_L4_100G: return snprintf(result, lmax, TRANSVR_IF_KR4); /* 40G Optical */ case TRANSVR_CLASS_OPTICAL_40G: case TRANSVR_CLASS_OPTICAL_40G_AOC: case TRANSVR_CLASS_OPTICAL_40G_SR4: case TRANSVR_CLASS_OPTICAL_40G_LR4: case TRANSVR_CLASS_OPTICAL_40G_ER4: return snprintf(result, lmax, TRANSVR_IF_SR4); /* 40G Copper */ case TRANSVR_CLASS_COPPER_L4_40G: return snprintf(result, lmax, TRANSVR_IF_KR4); /* 10G Optical */ case TRANSVR_CLASS_OPTICAL_10G: case TRANSVR_CLASS_OPTICAL_10G_Q_AOC: case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_OPTICAL_10G_Q_ER: return snprintf(result, lmax, TRANSVR_IF_SR4); /* Optical */ case TRANSVR_CLASS_OPTICAL: return snprintf(result, lmax, TRANSVR_IF_SR4); /* Copper */ case TRANSVR_CLASS_COPPER: return snprintf(result, lmax, TRANSVR_IF_KR4); default: snprintf(err_msg, sizeof(err_msg), "Detect undefined value:%d", transvr_cls); goto err_qsfp_set_trident2_if_type_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_qsfp_set_trident2_if_type_1; err_qsfp_set_trident2_if_type_1: snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); SWPS_INFO("%s: %s\n :%s", __func__, err_msg, self->swp_name); return ERR_TRANSVR_ABNORMAL; } int _qsfp_detect_if_type(struct transvr_obj_s* self, char *result){ int lmax = 8; int detect_cls = DEBUG_TRANSVR_INT_VAL; detect_cls = qsft_detect_transvr_class(self); switch (self->chipset_type) { case BCM_CHIP_TYPE_TRIDENT_2: return _qsfp_set_trident2_if_type(self, detect_cls, result); case BCM_CHIP_TYPE_TOMAHAWK: return _qsfp_set_tomahawk_if_type(self, detect_cls, result); default: SWPS_INFO("%s: non-defined chipset_type:%d :%s\n", __func__, self->chipset_type, self->swp_name); break; } snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); return ERR_TRANSVR_ABNORMAL; } int qsfp_get_if_type(struct transvr_obj_s *self, char *buf_p){ int lmax = 8; char tmp_result[8] = DEBUG_TRANSVR_STR_VAL; if (self->state != STATE_TRANSVR_CONNECTED) { return snprintf(buf_p, lmax, "%d\n", self->state); } if (_qsfp_detect_if_type(self, tmp_result) < 0) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL); } return snprintf(buf_p, lmax, "%s\n", tmp_result); } int _qsfp_detect_if_speed(struct transvr_obj_s* self, char *result){ int lmax = 16; int detect_val = DEBUG_TRANSVR_INT_VAL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; detect_val = qsft_detect_transvr_class(self); switch (detect_val) { case TRANSVR_CLASS_UNSPECIFIED: case TRANSVR_CLASS_ERROR: break; /* 100G Optical */ case TRANSVR_CLASS_OPTICAL_100G: case TRANSVR_CLASS_OPTICAL_100G_AOC: case TRANSVR_CLASS_OPTICAL_100G_SR4: case TRANSVR_CLASS_OPTICAL_100G_LR4: case TRANSVR_CLASS_OPTICAL_100G_ER4: case TRANSVR_CLASS_OPTICAL_100G_PSM4: return snprintf(result, lmax, TRANSVR_IF_SP_100G); /* 100G Copper */ case TRANSVR_CLASS_COPPER_L4_100G: return snprintf(result, lmax, TRANSVR_IF_SP_100G); /* 40G Optical */ case TRANSVR_CLASS_OPTICAL_40G: case TRANSVR_CLASS_OPTICAL_40G_AOC: case TRANSVR_CLASS_OPTICAL_40G_SR4: case TRANSVR_CLASS_OPTICAL_40G_LR4: case TRANSVR_CLASS_OPTICAL_40G_ER4: return snprintf(result, lmax, TRANSVR_IF_SP_40G); /* 40G Copper */ case TRANSVR_CLASS_COPPER_L4_40G: return snprintf(result, lmax, TRANSVR_IF_SP_40G); /* 10G Optical */ case TRANSVR_CLASS_OPTICAL_10G: case TRANSVR_CLASS_OPTICAL_10G_Q_AOC: case TRANSVR_CLASS_OPTICAL_10G_Q_SR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_OPTICAL_10G_Q_LR: /* Need Check: SR4 or SR */ case TRANSVR_CLASS_OPTICAL_10G_Q_ER: return snprintf(result, lmax, TRANSVR_IF_SP_10G); /* 10G Copper */ case TRANSVR_CLASS_COPPER_L4_10G: return snprintf(result, lmax, TRANSVR_IF_SP_10G); /* Optical */ case TRANSVR_CLASS_OPTICAL: break; /* Copper */ case TRANSVR_CLASS_COPPER: break; default: snprintf(err_msg, sizeof(err_msg), "Detect undefined class case:%d", detect_val); goto err_qsfp_detect_if_speed_1; } /* Check br and extbr */ detect_val = _qsfp_detect_if_sp_by_br(self); switch(detect_val) { case TRANSVR_CLASS_UNSPECIFIED: break; case TRANSVR_CLASS_10G: return snprintf(result, lmax, TRANSVR_IF_SP_10G); case TRANSVR_CLASS_40G: return snprintf(result, lmax, TRANSVR_IF_SP_40G); case TRANSVR_CLASS_100G: return snprintf(result, lmax, TRANSVR_IF_SP_100G); default: snprintf(err_msg, sizeof(err_msg), "Detect undefined BR case:%d", detect_val); goto err_qsfp_detect_if_speed_1; } /* Exception case: Can't verify */ snprintf(err_msg, sizeof(err_msg), "Can not identify!"); goto err_qsfp_detect_if_speed_1; err_qsfp_detect_if_speed_1: snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW); SWPS_INFO("%s: %s :%s\n", __func__, err_msg, self->swp_name); return ERR_TRANSVR_ABNORMAL; } int qsfp_get_if_speed(struct transvr_obj_s *self, char *buf_p){ int lmax = 16; char tmp_result[16] = DEBUG_TRANSVR_STR_VAL; if (self->state != STATE_TRANSVR_CONNECTED) { return snprintf(buf_p, lmax, "%d\n", self->state); } if (_qsfp_detect_if_speed(self, tmp_result) < 0) { return snprintf(buf_p, lmax, "%d\n", ERR_TRANSVR_ABNORMAL); } return snprintf(buf_p, lmax, "%s\n", tmp_result); } int _common_set_lane_map_str(struct transvr_obj_s* self, char *result) { int i = 0; int tmp_val = 0; char tmp_str[LEN_TRANSVR_L_STR] = DEBUG_TRANSVR_STR_VAL; char err_msg[LEN_TRANSVR_L_STR] = DEBUG_TRANSVR_STR_VAL; memset(result, 0, LEN_TRANSVR_L_STR); snprintf(result, LEN_TRANSVR_L_STR, "%s=", TRANSVR_UEVENT_KEY_LANE); for (i=0; ilane_id); i++) { tmp_val = self->lane_id[i]; if (tmp_val < 1) { break; } if (tmp_val > 256) { snprintf(err_msg, sizeof(err_msg), "detect abnormal value:%d", tmp_val); goto err_common_set_lane_map_str_1; } memset(tmp_str, 0, sizeof(tmp_str)); if (i == 0) { snprintf(tmp_str, LEN_TRANSVR_L_STR, "%d", tmp_val); } else { snprintf(tmp_str, LEN_TRANSVR_L_STR, ",%d", tmp_val); } strncat(result, tmp_str, LEN_TRANSVR_L_STR); } if (i == 0) { goto err_common_set_lane_map_str_2; } return 0; err_common_set_lane_map_str_1: SWPS_INFO("%s: %s", __func__, err_msg); err_common_set_lane_map_str_2: snprintf(result, LEN_TRANSVR_L_STR, "%s=%s", TRANSVR_UEVENT_KEY_LANE, TRANSVR_UEVENT_UNKNOW); return EVENT_TRANSVR_TASK_FAIL; } int _common_send_uevent(struct transvr_obj_s* self, enum kobject_action u_action, int (*detect_if_type)(struct transvr_obj_s *self, char *result), int (*detect_if_speed)(struct transvr_obj_s *self, char *result), int send_anyway) { char *uevent_envp[4]; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; char tmp_str[32] = DEBUG_TRANSVR_STR_VAL; char tmp_str_1[32] = DEBUG_TRANSVR_STR_VAL; char tmp_str_2[32] = DEBUG_TRANSVR_STR_VAL; char tmp_str_3[64] = DEBUG_TRANSVR_STR_VAL; if (TRANSVR_UEVENT_ENABLE != 1) { return ERR_TRANSVR_NOTSUPPORT; } if (_common_get_if_lane(self, tmp_str) < 0) { snprintf(tmp_str_3, sizeof(tmp_str_3), "%s=%s", TRANSVR_UEVENT_KEY_LANE, TRANSVR_UEVENT_UNKNOW); } else { snprintf(tmp_str_3, sizeof(tmp_str_3), "%s=%s", TRANSVR_UEVENT_KEY_LANE, tmp_str); } switch (u_action) { case KOBJ_ADD: /* Detect type */ if (detect_if_type(self, tmp_str) < 0) { snprintf(err_msg, sizeof(err_msg), "%s", "Detect interface type fail!"); snprintf(tmp_str_1, sizeof(tmp_str_1), "%s=%s", TRANSVR_UEVENT_KEY_IF, TRANSVR_UEVENT_UNKNOW); snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, TRANSVR_UEVENT_UNKNOW); uevent_envp[0] = tmp_str_1; uevent_envp[1] = tmp_str_2; uevent_envp[2] = tmp_str_3; uevent_envp[3] = NULL; goto private_common_send_uevent_4_fail; } snprintf(tmp_str_1, sizeof(tmp_str_1), "%s=%s", TRANSVR_UEVENT_KEY_IF, tmp_str); uevent_envp[0] = tmp_str_1; /* Detect speed */ if (detect_if_speed(self, tmp_str) < 0) { snprintf(err_msg, sizeof(err_msg), "%s", "Detect interface speed fail!"); snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, TRANSVR_UEVENT_UNKNOW); uevent_envp[1] = tmp_str_2; uevent_envp[2] = tmp_str_3; uevent_envp[3] = NULL; goto private_common_send_uevent_4_fail; } snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, tmp_str); uevent_envp[1] = tmp_str_2; uevent_envp[2] = tmp_str_3; uevent_envp[3] = NULL; goto private_common_send_uevent_4_send; case KOBJ_REMOVE: snprintf(tmp_str_1, sizeof(tmp_str_1), "%s=%s", TRANSVR_UEVENT_KEY_IF, TRANSVR_UEVENT_UNKNOW); snprintf(tmp_str_2, sizeof(tmp_str_2), "%s=%s", TRANSVR_UEVENT_KEY_SP, TRANSVR_UEVENT_UNKNOW); uevent_envp[0] = tmp_str_1; uevent_envp[1] = tmp_str_2; uevent_envp[2] = tmp_str_3; uevent_envp[3] = NULL; goto private_common_send_uevent_4_send; default: snprintf(err_msg, sizeof(err_msg), "kobject_action:%d not support", u_action); goto private_common_send_uevent_4_fail; } snprintf(err_msg, sizeof(err_msg), "%s", "Exception case"); goto private_common_send_uevent_4_fail; private_common_send_uevent_4_fail: SWPS_INFO("%s: %s :%s\n", __func__, err_msg, self->swp_name); if (send_anyway) { goto private_common_send_uevent_4_send; } return ERR_TRANSVR_UEVENT_FAIL; private_common_send_uevent_4_send: return kobject_uevent_env(&(self->transvr_dev_p->kobj), u_action, uevent_envp); } int sfp_send_uevent(struct transvr_obj_s* self, enum kobject_action u_action) { int send_anyway = 1; return _common_send_uevent(self, u_action, &_sfp_detect_if_type, &_sfp_detect_if_speed, send_anyway); } int qsfp_send_uevent(struct transvr_obj_s* self, enum kobject_action u_action) { int send_anyway = 1; return _common_send_uevent(self, u_action, &_qsfp_detect_if_type, &_qsfp_detect_if_speed, send_anyway); } int fake_send_uevent(struct transvr_obj_s* self, enum kobject_action u_action) { return EVENT_TRANSVR_TASK_DONE; } int common_fsm_4_direct_mode(struct transvr_obj_s* self, char *caller_name){ int err; int detect_result[2]; int current_state = STATE_TRANSVR_UNEXCEPTED; int current_type = TRANSVR_TYPE_ERROR; if (self->state == STATE_TRANSVR_NEW) { if (_transvr_init_handler(self) < 0){ return ERR_TRANSVR_INIT_FAIL; } } err = detect_transvr_state(self, detect_result); if (err < 0) { return err; } /* In Direct mode, driver only detect transceiver when user call driver interface * which on sysfs. So it only need consider the state of Transceiver. */ current_state = detect_result[0]; current_type = detect_result[1]; switch (current_state){ case STATE_TRANSVR_DISCONNECTED: /* Transceiver is not plugged */ self->state = current_state; self->type = current_type; return ERR_TRANSVR_UNPLUGGED; case STATE_TRANSVR_INIT: /* Transceiver is plugged, system not ready */ return ERR_TRANSVR_UNINIT; case STATE_TRANSVR_ISOLATED: /* Transceiver is plugged, but has some issues */ return ERR_TRNASVR_BE_ISOLATED; case STATE_TRANSVR_CONNECTED: /* Transceiver is plugged, system is ready */ self->state = current_state; self->type = current_type; return 0; case STATE_TRANSVR_SWAPPED: /* Transceiver is plugged, system detect user changed */ self->type = current_type; if (reload_transvr_obj(self, current_type) < 0){ self->state = STATE_TRANSVR_UNEXCEPTED; return ERR_TRANSVR_UNEXCPT; } self->state = current_state; return 0; case STATE_TRANSVR_UNEXCEPTED: /* Transceiver type or state is unexpected case */ self->state = STATE_TRANSVR_UNEXCEPTED; self->type = TRANSVR_TYPE_ERROR; return ERR_TRANSVR_UNEXCPT; default: SWPS_INFO("%s: state:%d not in define.\n", __func__, current_state); break; } return ERR_TRANSVR_UNEXCPT; } static int _is_except_happened_4_pmode(struct transvr_obj_s* self, int new_state) { int event_chk = 0; if (self->temp == 0){ return 0; } switch (new_state) { case STATE_TRANSVR_INIT: event_chk = EVENT_TRANSVR_EXCEP_INIT; goto check_event_happened_4_pmode; case STATE_TRANSVR_CONNECTED: event_chk = EVENT_TRANSVR_EXCEP_UP; goto check_event_happened_4_pmode; case STATE_TRANSVR_DISCONNECTED: event_chk = EVENT_TRANSVR_EXCEP_DOWN; goto check_event_happened_4_pmode; case STATE_TRANSVR_SWAPPED: event_chk = EVENT_TRANSVR_EXCEP_SWAP; goto check_event_happened_4_pmode; case STATE_TRANSVR_UNEXCEPTED: event_chk = EVENT_TRANSVR_EXCEP_EXCEP; goto check_event_happened_4_pmode; case STATE_TRANSVR_ISOLATED: event_chk = EVENT_TRANSVR_EXCEP_ISOLATED; goto check_event_happened_4_pmode; default: SWPS_INFO("%s: unexcepted case:%d\n", __func__, new_state); break; } return 0; check_event_happened_4_pmode: if (self->temp == event_chk){ return 1; } return 0; } int common_fsm_4_polling_mode(struct transvr_obj_s* self, char *caller_name){ /* [Return Value]: * ERR_TRANSVR_UNINIT : (1) Initial not ready * ERR_TRANSVR_UNPLUGGED : (1) Any -> Down * ERR_TRANSVR_TASK_BUSY : (1) Wait Initial task * ERR_TRANSVR_UNEXCPT : (1) Initial fail * (2) Task fail * (3) Reload fail * ERR_TRNASVR_BE_ISOLATED : (1) Already be isolated * OK Case (return 0) : (1) action_4_connected * (2) action_4_nothing (initial retry) */ int curr_state[2]; int old_state = self->state; int old_type = self->type; int new_state = STATE_TRANSVR_UNEXCEPTED; int new_type = TRANSVR_TYPE_ERROR; int return_val = ERR_TRANSVR_UNEXCPT; /* Never initial */ if (self->state == STATE_TRANSVR_NEW) { goto comfsm_action_4_reinit_obj; } /* Detect current state */ switch (detect_transvr_state(self, curr_state)) { case 0: new_state = curr_state[0]; new_type = curr_state[1]; break; case ERR_TRNASVR_BE_ISOLATED: new_state = STATE_TRANSVR_ISOLATED; new_type = old_type; break; case ERR_TRANSVR_I2C_CRASH: goto comfsm_action_4_report_i2c_crash; case ERR_TRANSVR_UNEXCPT: default: new_state = STATE_TRANSVR_UNEXCEPTED; new_type = old_type; } /* State handling */ switch (old_state) { case STATE_TRANSVR_INIT: /* INIT -> */ return_val = ERR_TRANSVR_UNINIT; goto comfsm_action_4_keep_state; case STATE_TRANSVR_CONNECTED: switch (new_state) { case STATE_TRANSVR_INIT: /* Case 1-1: UP -> INIT */ SWPS_INFO("Detect %s is present. :1-1\n",self->swp_name); return_val = ERR_TRANSVR_UNINIT; goto comfsm_action_4_keep_state; case STATE_TRANSVR_CONNECTED: /* Case 1-2: UP -> UP */ return_val = 0; goto comfsm_action_4_keep_state; case STATE_TRANSVR_DISCONNECTED: /* Case 1-3: UP -> DOWN */ SWPS_INFO("Detect %s is removed. :1-3\n",self->swp_name); goto comfsm_action_4_disconnected; case STATE_TRANSVR_SWAPPED: /* Case 1-4: UP -> SWAP */ SWPS_INFO("Detect %s is swapped. :1-4\n",self->swp_name); goto comfsm_action_4_reload_obj; case STATE_TRANSVR_UNEXCEPTED: /* Case 1-5: UP -> UNEXPET */ SWPS_INFO("Detect %s has error. :1-5\n",self->swp_name); goto comfsm_action_4_unexpected; case STATE_TRANSVR_ISOLATED: /* Case 1-6: UP -> ISOLATE */ SWPS_INFO("Detect %s be isolated. :1-6\n",self->swp_name); goto comfsm_action_4_isolate_obj; default: break; } goto comfsm_action_4_unexpected; case STATE_TRANSVR_DISCONNECTED: switch (new_state) { case STATE_TRANSVR_INIT: /* Case 2-1: DOWN -> INIT */ SWPS_INFO("Detect %s is present. :2-1\n",self->swp_name); return_val = ERR_TRANSVR_UNINIT; goto comfsm_action_4_keep_state; case STATE_TRANSVR_CONNECTED: /* Case 2-2: DOWN -> UP */ SWPS_INFO("Detect %s is present. :2-2\n",self->swp_name); goto comfsm_action_4_reinit_obj; case STATE_TRANSVR_DISCONNECTED: /* Case 2-3: DOWN -> DOWN */ return_val = ERR_TRANSVR_UNPLUGGED; goto comfsm_action_4_keep_state; case STATE_TRANSVR_SWAPPED: /* Case 2-4: DOWN -> SWAP */ SWPS_INFO("Detect %s is swapped. :2-4\n",self->swp_name); goto comfsm_action_4_reload_obj; case STATE_TRANSVR_UNEXCEPTED: /* Case 2-5: DOWN -> UNEXPET */ SWPS_INFO("Detect %s has error. :2-5\n",self->swp_name); goto comfsm_action_4_unexpected; case STATE_TRANSVR_ISOLATED: /* Case 2-6: DOWN -> ISOLATE */ SWPS_INFO("Detect %s be isolated. :2-6\n",self->swp_name); goto comfsm_action_4_isolate_obj; default: break; } goto comfsm_action_4_unexpected; case STATE_TRANSVR_UNEXCEPTED: /* Filter out re-action */ if (_is_except_happened_4_pmode(self, new_state)) { goto comfsm_action_4_keep_state; } /* First action */ switch (new_state) { case STATE_TRANSVR_INIT: /* Case 3-1: UNEXPET -> INIT */ SWPS_INFO("Detect %s is present. :3-1\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_INIT; return_val = ERR_TRANSVR_UNINIT; goto comfsm_action_4_keep_state; case STATE_TRANSVR_CONNECTED: /* Case 3-2: UNEXPET -> UP */ SWPS_INFO("Detect %s is present. :3-2\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_UP; goto comfsm_action_4_reload_obj; case STATE_TRANSVR_DISCONNECTED: /* Case 3-3: UNEXPET -> DOWN */ SWPS_INFO("Detect %s is removed. :3-3\n",self->swp_name); goto comfsm_action_4_disconnected; case STATE_TRANSVR_SWAPPED: /* Case 3-4: UNEXPET -> SWAP */ SWPS_INFO("Detect %s is swapped. :3-4\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_SWAP; goto comfsm_action_4_reload_obj; case STATE_TRANSVR_UNEXCEPTED: /* Case 3-5: UNEXPET -> UNEXPET */ self->temp = EVENT_TRANSVR_EXCEP_EXCEP; return_val = ERR_TRANSVR_UNEXCPT; goto comfsm_action_4_keep_state; case STATE_TRANSVR_ISOLATED: /* Case 3-6: UNEXPET -> ISOLATE */ SWPS_INFO("Detect %s be isolated. :3-6\n",self->swp_name); goto comfsm_action_4_isolate_obj; default: break; } goto comfsm_action_4_unexpected; case STATE_TRANSVR_ISOLATED: /* Filter out re-action */ if (_is_except_happened_4_pmode(self, new_state)) { goto comfsm_action_4_keep_state; } /* First action */ switch (new_state) { case STATE_TRANSVR_INIT: /* Case 4-1: ISOLATE -> INIT */ SWPS_INFO("Detect %s internal error. :4-1\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_INIT; return_val = ERR_TRNASVR_BE_ISOLATED; goto comfsm_action_4_keep_state; case STATE_TRANSVR_CONNECTED: /* Case 4-2: ISOLATE -> UP */ SWPS_INFO("Detect %s internal error. :4-2\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_UP; return_val = ERR_TRNASVR_BE_ISOLATED; goto comfsm_action_4_keep_state; case STATE_TRANSVR_DISCONNECTED: /* Case 4-3: ISOLATE -> DOWN */ SWPS_INFO("Detect %s is removed. :4-3\n",self->swp_name); goto comfsm_action_4_disconnected; case STATE_TRANSVR_SWAPPED: /* Case 4-4: ISOLATE -> SWAP */ SWPS_INFO("Detect %s internal error. :4-4\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_SWAP; return_val = ERR_TRNASVR_BE_ISOLATED; goto comfsm_action_4_keep_state; case STATE_TRANSVR_UNEXCEPTED: /* Case 4-5: ISOLATE -> UNEXPET */ SWPS_INFO("Detect %s internal error. :4-5\n",self->swp_name); self->temp = EVENT_TRANSVR_EXCEP_EXCEP; return_val = ERR_TRNASVR_BE_ISOLATED; goto comfsm_action_4_keep_state; case STATE_TRANSVR_ISOLATED: /* Case 4-6: ISOLATE -> ISOLATE */ return_val = ERR_TRNASVR_BE_ISOLATED; goto comfsm_action_4_keep_state; default: break; } goto comfsm_action_4_unexpected; default: break; } goto comfsm_action_4_unexpected; comfsm_action_4_keep_state: return return_val; comfsm_action_4_reinit_obj: SWPS_DEBUG("FSM action: %s re-initial.\n", self->swp_name); return_val = _transvr_init_handler(self); goto comfsm_action_4_identify_event; comfsm_action_4_reload_obj: SWPS_DEBUG("FSM action: %s reload.\n", self->swp_name); self->type = new_type; return_val = reload_transvr_obj(self, new_type); goto comfsm_action_4_identify_event; comfsm_action_4_identify_event: switch (return_val) { case EVENT_TRANSVR_INIT_UP: case EVENT_TRANSVR_TASK_DONE: goto comfsm_action_4_connected; case EVENT_TRANSVR_INIT_DOWN: goto comfsm_action_4_disconnected; case EVENT_TRANSVR_INIT_REINIT: goto comfsm_action_4_nothing; case EVENT_TRANSVR_TASK_WAIT: self->state = STATE_TRANSVR_INIT; return ERR_TRANSVR_TASK_BUSY; case EVENT_TRANSVR_TASK_FAIL: SWPS_INFO("%s detect EVENT_TRANSVR_TASK_FAIL.\n", self->swp_name); goto comfsm_action_4_unexpected; case EVENT_TRANSVR_INIT_FAIL: SWPS_INFO("%s detect EVENT_TRANSVR_INIT_FAIL.\n", self->swp_name); goto comfsm_action_4_unexpected; case EVENT_TRANSVR_RELOAD_FAIL: SWPS_INFO("%s detect EVENT_TRANSVR_RELOAD_FAIL.\n", self->swp_name); goto comfsm_action_4_unexpected; case EVENT_TRANSVR_I2C_CRASH: goto comfsm_action_4_report_i2c_crash; case EVENT_TRANSVR_EXCEP_ISOLATED: goto comfsm_action_4_isolate_obj; default: SWPS_INFO("%s detect undefined event:%d.\n", self->swp_name, return_val); goto comfsm_action_4_unexpected; } comfsm_action_4_nothing: SWPS_DEBUG("FSM action: %s do nothing.\n", self->swp_name); return 0; comfsm_action_4_connected: SWPS_DEBUG("FSM action: %s Connected.\n", self->swp_name); self->state = STATE_TRANSVR_CONNECTED; self->type = new_type; self->send_uevent(self, KOBJ_ADD); _transvr_clean_retry(self); return 0; comfsm_action_4_disconnected: SWPS_DEBUG("FSM action: %s Disconnected. \n", self->swp_name); self->state = STATE_TRANSVR_DISCONNECTED; self->temp = EVENT_TRANSVR_TASK_DONE; self->send_uevent(self, KOBJ_REMOVE); _transvr_clean_retry(self); _transvr_clean_handler(self); return ERR_TRANSVR_UNPLUGGED; comfsm_action_4_report_i2c_crash: SWPS_DEBUG("FSM action: %s report I2C crash.\n", self->swp_name); self->state = STATE_TRANSVR_UNEXCEPTED; return ERR_TRANSVR_I2C_CRASH; comfsm_action_4_isolate_obj: SWPS_DEBUG("FSM action: %s isolate.\n", self->swp_name); self->state = STATE_TRANSVR_ISOLATED; return ERR_TRNASVR_BE_ISOLATED; comfsm_action_4_unexpected: SWPS_INFO("FSM action: %s unexpected.\n", self->swp_name); SWPS_INFO("Dump: :%d :0x%02x :%d :0x%02x\n", old_state, old_type, new_state, new_type); self->state = STATE_TRANSVR_UNEXCEPTED; self->send_uevent(self, KOBJ_REMOVE); _transvr_clean_handler(self); return ERR_TRANSVR_UNEXCPT; } int fake_fsm_4_direct_mode(struct transvr_obj_s* self, char *caller_name){ self->state = STATE_TRANSVR_CONNECTED; self->type = TRANSVR_TYPE_FAKE; return 0; } int fake_fsm_4_polling_mode(struct transvr_obj_s* self, char *caller_name){ self->state = STATE_TRANSVR_CONNECTED; self->type = TRANSVR_TYPE_FAKE; return 0; } /* ========== Object functions for Initial procedure ========== */ int transvr_init_common(struct transvr_obj_s *self){ /* Nothing to update */ return EVENT_TRANSVR_TASK_DONE; } int transvr_init_fake(struct transvr_obj_s *self){ return EVENT_TRANSVR_TASK_DONE; } int transvr_init_sfp(struct transvr_obj_s *self){ int tmp_val = DEBUG_TRANSVR_INT_VAL; int err_code = DEBUG_TRANSVR_INT_VAL; char *err_msg = "ERR"; self->info = sft_detect_transvr_class(self); /* Disable auto_config */ if (!self->auto_config) { return EVENT_TRANSVR_TASK_DONE; } /* Handle multi-rate */ err_code = initfunc_sfp_handle_multi_rate_mode(self); if (err_code < 0) { err_msg = "initfunc_sfp_handle_multi_rate_mode fail!"; goto err_transvr_init_sfp_1; } /* Handle 1G- RJ45 */ tmp_val = err_code; err_code = initfunc_sfp_handle_1g_rj45(self); if (err_code < 0) { err_msg = "initfunc_sfp_handle_1g_rj45 fail!"; goto err_transvr_init_sfp_1; } tmp_val = (tmp_val > err_code ? tmp_val : err_code); if (tmp_val > EVENT_TRANSVR_TASK_DONE) { return tmp_val; } return EVENT_TRANSVR_TASK_DONE; err_transvr_init_sfp_1: SWPS_INFO("%s: %s :%d :%s\n", __func__, err_msg, err_code, self->swp_name); return EVENT_TRANSVR_INIT_FAIL; } int transvr_init_qsfp(struct transvr_obj_s *self){ int err = EVENT_TRANSVR_EXCEP_EXCEP; char *emsg = "ERR"; self->info = qsft_detect_transvr_class(self); if (!self->auto_config) { return EVENT_TRANSVR_TASK_DONE; } err = initfunc_qsfp_handle_power_mode(self); if (err < 0){ emsg = "initfunc_qsfp_handle_tx_disable fail!"; goto err_transvr_init_qsfp; } return EVENT_TRANSVR_TASK_DONE; err_transvr_init_qsfp: SWPS_INFO("%s: %s :%d :%s\n", __func__, emsg, err, self->swp_name); return EVENT_TRANSVR_INIT_FAIL; } int transvr_init_qsfp28(struct transvr_obj_s *self){ int tmp_val = EVENT_TRANSVR_EXCEP_EXCEP; int err_val = EVENT_TRANSVR_EXCEP_EXCEP; char *err_msg = "ERR"; /* Handle QSFP common */ err_val = transvr_init_qsfp(self); if (err_val < 0){ err_msg = "transvr_init_qsfp fail!"; goto err_transvr_init_qsfp28_1; } /* Disable auto_config */ if (!self->auto_config) { return err_val; } /* Handle CDR */ tmp_val = err_val; err_val = initfunc_qsfp28_handle_cdr(self); if (err_val < 0){ err_msg = "Handle CDR fail!"; goto err_transvr_init_qsfp28_1; } tmp_val = (tmp_val > err_val ? tmp_val : err_val); if (tmp_val > EVENT_TRANSVR_TASK_DONE) { return tmp_val; } return EVENT_TRANSVR_TASK_DONE; err_transvr_init_qsfp28_1: SWPS_INFO("%s: %s :%d :%s\n", __func__, err_msg, err_val, self->swp_name); return EVENT_TRANSVR_INIT_FAIL; } /* ========== Object Initial handler ========== */ static int _is_transvr_valid(struct transvr_obj_s *self, int type, int state) { /* [Return] * 0 : OK, inserted * EVENT_TRANSVR_INIT_DOWN : OK, removed * EVENT_TRANSVR_INIT_FAIL : Outside error, type doesn't supported * EVENT_TRANSVR_EXCEP_INIT : Internal error, state undefined */ switch (type) { case TRANSVR_TYPE_SFP: case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: case TRANSVR_TYPE_QSFP_28: case TRANSVR_TYPE_UNPLUGGED: case TRANSVR_TYPE_FAKE: break; default: SWPS_INFO("detect undefined type:0x%02x on %s\n", type, self->swp_name); return EVENT_TRANSVR_INIT_FAIL; } switch (state) { case STATE_TRANSVR_DISCONNECTED: return EVENT_TRANSVR_INIT_DOWN; case STATE_TRANSVR_INIT: case STATE_TRANSVR_CONNECTED: case STATE_TRANSVR_SWAPPED: break; default: SWPS_INFO("detect undefined state:%d on %s\n", state, self->swp_name); return EVENT_TRANSVR_EXCEP_INIT; } return 0; } static int _is_transvr_hw_ready(struct transvr_obj_s *self, int type){ /* [Return] * EVENT_TRANSVR_TASK_DONE : Ready * EVENT_TRANSVR_TASK_WAIT : Not ready * EVENT_TRANSVR_INIT_FAIL : Error */ int addr = DEBUG_TRANSVR_INT_VAL; int page = DEBUG_TRANSVR_INT_VAL; int offs = DEBUG_TRANSVR_INT_VAL; int bit = DEBUG_TRANSVR_INT_VAL; int ready = DEBUG_TRANSVR_INT_VAL; int err = DEBUG_TRANSVR_INT_VAL; char *emsg = DEBUG_TRANSVR_STR_VAL; uint8_t ab_val = DEBUG_TRANSVR_HEX_VAL; switch (type) { case TRANSVR_TYPE_SFP: addr = VAL_TRANSVR_8472_READY_ADDR; page = VAL_TRANSVR_8472_READY_PAGE; offs = VAL_TRANSVR_8472_READY_OFFSET; bit = VAL_TRANSVR_8472_READY_BIT; ready = VAL_TRANSVR_8472_READY_VALUE; ab_val = VAL_TRANSVR_8472_READY_ABNORMAL; break; case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: case TRANSVR_TYPE_QSFP_28: addr = VAL_TRANSVR_8436_READY_ADDR; page = VAL_TRANSVR_8436_READY_PAGE; offs = VAL_TRANSVR_8436_READY_OFFSET; bit = VAL_TRANSVR_8436_READY_BIT; ready = VAL_TRANSVR_8436_READY_VALUE; ab_val = VAL_TRANSVR_8436_READY_ABNORMAL; break; case TRANSVR_TYPE_UNPLUGGED: case TRANSVR_TYPE_FAKE: return EVENT_TRANSVR_TASK_DONE; default: emsg = "unexpected case"; goto err_is_transvr_hw_ready; } /* Select target page */ err = _common_setup_page(self, addr, page, offs, 1, 0); if (err < 0) { emsg = "setup page fail"; goto err_is_transvr_hw_ready; } /* Check feature supported * [Note] * Some of transceiver/cables doesn't support "Status Indicators" * (ex:DAC, RJ45 copper SFP ...etc). In these case, we bypass the * step of checking Status Indicators, then state machine will take * the following handle procedure. */ err = i2c_smbus_read_byte_data(self->i2c_client_p, VAL_TRANSVR_COMID_OFFSET); if (err < 0) { emsg = "doesn't support Status Indicators"; goto bypass_is_transvr_hw_ready; } /* Filter abnormal case */ if (err == ab_val) { emsg = "detect using unusual definition."; goto bypass_is_transvr_hw_ready; } /* Get Status Indicators */ err = i2c_smbus_read_byte_data(self->i2c_client_p, offs); if (err < 0) { emsg = "detect current value fail"; goto err_is_transvr_hw_ready; } if ((err & (1<:%d\n", __func__, emsg, type); return EVENT_TRANSVR_TASK_DONE; err_is_transvr_hw_ready: SWPS_DEBUG("%s: %s :%d\n", __func__, emsg, type); return EVENT_TRANSVR_INIT_FAIL; } static int _is_transvr_support_ctle(struct transvr_obj_s *self) { switch (self->info) { case TRANSVR_CLASS_OPTICAL_25G: case TRANSVR_CLASS_OPTICAL_25G_AOC: case TRANSVR_CLASS_OPTICAL_25G_SR: case TRANSVR_CLASS_OPTICAL_25G_LR: case TRANSVR_CLASS_OPTICAL_25G_ER: case TRANSVR_CLASS_OPTICAL_100G: case TRANSVR_CLASS_OPTICAL_100G_AOC: case TRANSVR_CLASS_OPTICAL_100G_SR4: case TRANSVR_CLASS_OPTICAL_100G_LR4: case TRANSVR_CLASS_OPTICAL_100G_ER4: case TRANSVR_CLASS_OPTICAL_100G_PSM4: return 1; default: break; } return 0; } static int _transvr_init_handler(struct transvr_obj_s *self){ int detect[2]; int d_state = STATE_TRANSVR_UNEXCEPTED; int d_type = TRANSVR_TYPE_ERROR; int result = ERR_TRANSVR_UNINIT; int retry = 6; /* (6+1) x 0.3 = 2.1s > spec:2.0s */ int elimit = 63; char emsg[64] = DEBUG_TRANSVR_STR_VAL; /* Clean and check callback */ self->state = STATE_TRANSVR_INIT; if (self->init == NULL) { snprintf(emsg, elimit, "init() is null"); goto initer_err_case_unexcept_0; } if (self->clean == NULL) { snprintf(emsg, elimit, "clean() is null"); goto initer_err_case_unexcept_0; } self->clean(self); /* Detect transceiver information */ result = detect_transvr_state(self, detect); if (result < 0) { snprintf(emsg, elimit, "detect_transvr_state() fail"); switch (result) { case ERR_TRANSVR_I2C_CRASH: goto initer_err_case_i2c_ceash; case ERR_TRNASVR_BE_ISOLATED: goto initer_err_case_be_isolated; case ERR_TRANSVR_UNEXCPT: default: break; } goto initer_err_case_retry_1; } d_state = detect[0]; d_type = detect[1]; /* Verify transceiver type and state */ switch (_is_transvr_valid(self, d_type, d_state)) { case 0: break; case EVENT_TRANSVR_INIT_DOWN: goto initer_ok_case_down;; case EVENT_TRANSVR_INIT_FAIL: snprintf(emsg, elimit, "transceiver type doesn't support"); goto initer_err_case_alarm_to_user; case EVENT_TRANSVR_EXCEP_INIT: default: goto initer_err_case_unexcept_1; } /* Handle reload case */ if (self->type != d_type){ /* This is the protect mechanism. Normally, This case will not happen. * When State machine detect swap event during initial, It will trigger * reload function to ensure type correct. */ if (_reload_transvr_obj(self, d_type) < 0){ snprintf(emsg, elimit, "reload object fail"); goto initer_err_case_unexcept_1; } } /* Check transceiver HW initial ready */ switch (_is_transvr_hw_ready(self, d_type)) { case EVENT_TRANSVR_TASK_DONE: break; case EVENT_TRANSVR_TASK_WAIT: goto initer_err_case_retry_1; case EVENT_TRANSVR_INIT_FAIL: default: goto initer_err_case_unexcept_1; } /* Try to update all and check */ if (self->update_all(self, 1) < 0){ /* For some transceiver, EEPROME has lag issues during initial stage. * In this case, we set status back to STATE_TRANSVR_NEW, than it will * be checked in next polling cycle. */ goto initer_err_case_retry_1; } /* Execute init() call back */ result = self->init(self); switch (result) { case EVENT_TRANSVR_TASK_DONE: break; case EVENT_TRANSVR_TASK_WAIT: goto initer_ok_case_wait; default: snprintf(emsg, elimit, "undefined init() return:%d\n", result); goto initer_err_case_unexcept_1; } goto initer_ok_case_up; initer_ok_case_wait: self->dump_all(self); return EVENT_TRANSVR_TASK_WAIT; initer_ok_case_up: self->state = STATE_TRANSVR_CONNECTED; self->temp = 0; self->dump_all(self); return EVENT_TRANSVR_INIT_UP; initer_ok_case_down: self->temp = 0; self->state = STATE_TRANSVR_DISCONNECTED; return EVENT_TRANSVR_INIT_DOWN; initer_err_case_i2c_ceash: SWPS_DEBUG("%s: %s :%s :I2C crash\n", __func__, emsg, self->swp_name); self->state = STATE_TRANSVR_UNEXCEPTED; return EVENT_TRANSVR_I2C_CRASH; initer_err_case_be_isolated: SWPS_DEBUG("%s: %s :%s :isolated\n", __func__, emsg, self->swp_name); self->state = STATE_TRANSVR_ISOLATED; return EVENT_TRANSVR_EXCEP_ISOLATED; initer_err_case_retry_1: SWPS_DEBUG("%s: %s :%s :retry\n", __func__, emsg, self->swp_name); if (_transvr_handle_retry(self, retry) == 0) { self->state = STATE_TRANSVR_NEW; return EVENT_TRANSVR_INIT_REINIT; } goto initer_err_case_alarm_to_user; initer_err_case_unexcept_1: self->clean(self); initer_err_case_unexcept_0: self->state = STATE_TRANSVR_UNEXCEPTED; if (_is_except_happened_4_pmode(self, d_state) && (self->mode == TRANSVR_MODE_POLLING) ){ SWPS_INFO("%s: %s :%s\n", __func__, emsg, self->swp_name); SWPS_INFO("Dump: :%d :%d :%d :%d\n", self->state, self->type, d_state, d_type); } return EVENT_TRANSVR_INIT_FAIL; initer_err_case_alarm_to_user: SWPS_DEBUG("%s: %s :%s :alarm_to_user\n", __func__, emsg, self->swp_name); self->state = STATE_TRANSVR_UNEXCEPTED; alarm_msg_2_user(self, "detected transceiver/cables not meet SFF standard"); return EVENT_TRANSVR_INIT_FAIL; } /* ========== Object functions for Clean procedure ========== */ int _transvr_clean_handler(struct transvr_obj_s *self){ int retval = DEBUG_TRANSVR_INT_VAL; if (!self->clean) { SWPS_ERR("%s: %s clean() is NULL.\n", __func__, self->swp_name); return EVENT_TRANSVR_TASK_FAIL; } retval = self->clean(self); if (retval != EVENT_TRANSVR_TASK_DONE){ SWPS_ERR("%s: %s clean() fail. [ERR]:%d\n", __func__, self->swp_name, retval); return retval; } return EVENT_TRANSVR_TASK_DONE; } int common_transvr_clean(struct transvr_obj_s *self){ transvr_task_free_all(self); return EVENT_TRANSVR_TASK_DONE; } int qsfp_transvr_clean(struct transvr_obj_s *self){ int retval; int lpower_config = 1; retval = _taskfunc_qsfp_setup_power_mod(self, lpower_config); if (retval < 0){ SWPS_ERR("%s: Set lpmod fail! :%d\n", __func__, retval); return retval; } retval = common_transvr_clean(self); if (retval < 0){ SWPS_ERR("%s: common_transvr_clean fail! :%d\n", __func__, retval); return retval; } return EVENT_TRANSVR_TASK_DONE; } int fake_transvr_clean(struct transvr_obj_s *self){ return EVENT_TRANSVR_TASK_DONE; } /* ========== Object functions for check and update ========== */ int common_transvr_check(struct transvr_obj_s *self){ char fun_str[32] = "common_transvr_check"; if (self->mode != TRANSVR_MODE_POLLING) { SWPS_ERR("%s: mode:%d is not TRANSVR_MODE_POLLING\n", fun_str, self->mode); return ERR_TRANSVR_UNEXCPT; } /* Trigger delay task */ transvr_task_run_all(self); /* Trigger state machine to check and update */ return self->fsm_4_polling(self, fun_str); } int fake_transvr_check(struct transvr_obj_s *self){ return 0; } /* ========== Functions for Factory pattern ========== */ static int setup_transvr_public_cb(struct transvr_obj_s *self, int transvr_type){ switch (transvr_type){ case TRANSVR_TYPE_SFP: self->get_id = common_get_id; self->get_ext_id = common_get_ext_id; self->get_connector = common_get_connector; self->get_vendor_name = common_get_vendor_name; self->get_vendor_pn = common_get_vendor_pn; self->get_vendor_rev = common_get_vendor_rev; self->get_vendor_sn = common_get_vendor_sn; self->get_power_cls = unsupported_get_func; self->get_br = common_get_br; self->get_len_sm = sfp_get_len_sm; self->get_len_smf = common_get_len_smf; self->get_len_om1 = common_get_len_om1; self->get_len_om2 = common_get_len_om2; self->get_len_om3 = common_get_len_om3; self->get_len_om4 = common_get_len_om4; self->get_comp_rev = common_get_comp_rev; self->get_comp_eth_1 = sfp_get_comp_eth_1; self->get_comp_eth_10 = sfp_get_comp_eth_10; self->get_comp_eth_10_40 = unsupported_get_func; self->get_comp_extend = common_get_comp_extended; self->get_cdr = unsupported_get_func; self->get_rate_id = sfp_get_rate_id; self->get_soft_rs0 = sfp_get_soft_rs0; self->get_soft_rs1 = sfp_get_soft_rs1; self->get_info = common_get_info; self->get_if_type = sfp_get_if_type; self->get_if_speed = sfp_get_if_speed; self->get_if_lane = common_get_if_lane; self->get_curr_temp = sfp_get_transvr_temp; self->get_curr_vol = sfp_get_transvr_voltage; self->get_soft_rx_los = unsupported_get_func2; self->get_soft_tx_disable = unsupported_get_func2; self->get_soft_tx_fault = unsupported_get_func2; self->get_auto_tx_disable = unsupported_get_func2; self->get_tx_bias = sfp_get_transvr_tx_bias; self->get_tx_power = sfp_get_transvr_tx_power; self->get_rx_power = sfp_get_transvr_rx_power; self->get_tx_eq = sfp_get_transvr_tx_eq; self->get_rx_am = unsupported_get_func2; self->get_rx_em = sfp_get_transvr_rx_em; self->get_wavelength = sfp_get_wavelength; self->set_cdr = unsupported_set_func; self->set_soft_rs0 = sfp_set_soft_rs0; self->set_soft_rs1 = sfp_set_soft_rs1; self->set_soft_tx_disable = unsupported_set_func; self->set_auto_tx_disable = unsupported_set_func; self->set_tx_eq = sfp_set_tx_eq; self->set_rx_am = unsupported_set_func; self->set_rx_em = sfp_set_rx_em; return 0; case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: self->get_id = common_get_id; self->get_ext_id = common_get_ext_id; self->get_connector = common_get_connector; self->get_vendor_name = common_get_vendor_name; self->get_vendor_pn = common_get_vendor_pn; self->get_vendor_rev = common_get_vendor_rev; self->get_vendor_sn = common_get_vendor_sn; self->get_power_cls = qsfp_get_power_cls; self->get_br = common_get_br; self->get_len_sm = unsupported_get_func; self->get_len_smf = common_get_len_smf; self->get_len_om1 = common_get_len_om1; self->get_len_om2 = common_get_len_om2; self->get_len_om3 = common_get_len_om3; self->get_len_om4 = common_get_len_om4; self->get_comp_rev = common_get_comp_rev; self->get_comp_eth_1 = qsfp_get_comp_eth; self->get_comp_eth_10 = unsupported_get_func; self->get_comp_eth_10_40 = qsfp_get_comp_10_40; self->get_comp_extend = common_get_comp_extended; self->get_cdr = unsupported_get_func; self->get_rate_id = unsupported_get_func; self->get_soft_rs0 = unsupported_get_func; /* TBD */ self->get_soft_rs1 = unsupported_get_func; /* TBD */ self->get_info = common_get_info; self->get_if_type = qsfp_get_if_type; self->get_if_speed = qsfp_get_if_speed; self->get_if_lane = common_get_if_lane; self->get_curr_temp = qsfp_get_transvr_temp; self->get_curr_vol = qsfp_get_transvr_voltage; self->get_soft_rx_los = qsfp_get_soft_rx_los; self->get_soft_tx_disable = qsfp_get_soft_tx_disable; self->get_soft_tx_fault = qsfp_get_soft_tx_fault; self->get_auto_tx_disable = qsfp_get_auto_tx_disable; self->get_tx_bias = qsfp_get_transvr_tx_bias; self->get_tx_power = qsfp_get_transvr_tx_power; self->get_rx_power = qsfp_get_transvr_rx_power; self->get_tx_eq = unsupported_get_func2; self->get_rx_am = unsupported_get_func2; self->get_rx_em = unsupported_get_func2; self->get_wavelength = qsfp_get_wavelength; self->set_cdr = unsupported_set_func; self->set_soft_rs0 = unsupported_set_func; /* TBD */ self->set_soft_rs1 = unsupported_set_func; /* TBD */ self->set_soft_tx_disable = qsfp_set_soft_tx_disable; self->set_auto_tx_disable = qsfp_set_auto_tx_disable; self->set_tx_eq = unsupported_set_func; self->set_rx_am = unsupported_set_func; self->set_rx_em = unsupported_set_func; return 0; case TRANSVR_TYPE_QSFP_28: self->get_id = common_get_id; self->get_ext_id = common_get_ext_id; self->get_connector = common_get_connector; self->get_vendor_name = common_get_vendor_name; self->get_vendor_pn = common_get_vendor_pn; self->get_vendor_rev = common_get_vendor_rev; self->get_vendor_sn = common_get_vendor_sn; self->get_power_cls = qsfp_get_power_cls; self->get_br = common_get_br; self->get_len_sm = unsupported_get_func; self->get_len_smf = common_get_len_smf; self->get_len_om1 = common_get_len_om1; self->get_len_om2 = common_get_len_om2; self->get_len_om3 = common_get_len_om3; self->get_len_om4 = common_get_len_om4; self->get_comp_rev = common_get_comp_rev; self->get_comp_eth_1 = qsfp_get_comp_eth; self->get_comp_eth_10 = unsupported_get_func; self->get_comp_eth_10_40 = qsfp_get_comp_10_40; self->get_comp_extend = common_get_comp_extended; self->get_cdr = qsfp_get_cdr; self->get_rate_id = unsupported_get_func; self->get_soft_rs0 = unsupported_get_func; /* TBD */ self->get_soft_rs1 = unsupported_get_func; /* TBD */ self->get_info = common_get_info; self->get_if_type = qsfp_get_if_type; self->get_if_speed = qsfp_get_if_speed; self->get_if_lane = common_get_if_lane; self->get_curr_temp = qsfp_get_transvr_temp; self->get_curr_vol = qsfp_get_transvr_voltage; self->get_soft_rx_los = qsfp_get_soft_rx_los; self->get_soft_tx_disable = qsfp_get_soft_tx_disable; self->get_soft_tx_fault = qsfp_get_soft_tx_fault; self->get_auto_tx_disable = qsfp_get_auto_tx_disable; self->get_tx_bias = qsfp_get_transvr_tx_bias; self->get_tx_power = qsfp_get_transvr_tx_power; self->get_rx_power = qsfp_get_transvr_rx_power; self->get_tx_eq = qsfp_get_transvr_tx_eq; self->get_rx_am = qsfp_get_transvr_rx_am; self->get_rx_em = qsfp_get_transvr_rx_em; self->get_wavelength = qsfp_get_wavelength; self->set_cdr = qsfp_set_cdr; self->set_soft_rs0 = unsupported_set_func; /* TBD */ self->set_soft_rs1 = unsupported_set_func; /* TBD */ self->set_soft_tx_disable = qsfp_set_soft_tx_disable; self->set_auto_tx_disable = qsfp_set_auto_tx_disable; self->set_tx_eq = qsfp_set_tx_eq; self->set_rx_am = qsfp_set_rx_am; self->set_rx_em = qsfp_set_rx_em; return 0; case TRANSVR_TYPE_FAKE: self->get_id = fake_get_hex; self->get_ext_id = fake_get_hex; self->get_connector = fake_get_hex; self->get_vendor_name = fake_get_str; self->get_vendor_pn = fake_get_str; self->get_vendor_rev = fake_get_str; self->get_vendor_sn = fake_get_str; self->get_power_cls = fake_get_int; self->get_br = fake_get_hex; self->get_len_sm = fake_get_int; self->get_len_smf = fake_get_int; self->get_len_om1 = fake_get_int; self->get_len_om2 = fake_get_int; self->get_len_om3 = fake_get_int; self->get_len_om4 = fake_get_int; self->get_comp_rev = fake_get_hex; self->get_comp_eth_1 = fake_get_hex; self->get_comp_eth_10 = fake_get_hex; self->get_comp_eth_10_40 = fake_get_hex; self->get_comp_extend = fake_get_hex; self->get_cdr = fake_get_hex; self->get_rate_id = fake_get_hex; self->get_soft_rs0 = fake_get_binary; self->get_soft_rs1 = fake_get_binary; self->get_info = fake_get_int; self->get_if_type = fake_get_str; self->get_if_speed = fake_get_str; self->get_if_lane = fake_get_str; self->get_curr_temp = fake_get_str; self->get_curr_vol = fake_get_str; self->get_soft_rx_los = fake_get_str; self->get_soft_tx_disable = fake_get_str; self->get_soft_tx_fault = fake_get_str; self->get_auto_tx_disable = fake_get_str; self->get_tx_bias = fake_get_str; self->get_tx_power = fake_get_str; self->get_rx_power = fake_get_str; self->get_tx_eq = fake_get_str; self->get_rx_am = fake_get_str; self->get_rx_em = fake_get_str; self->get_wavelength = fake_get_str; self->set_cdr = fake_set_hex; self->set_soft_rs0 = fake_set_int; self->set_soft_rs1 = fake_set_int; self->set_soft_tx_disable = fake_set_int; self->set_auto_tx_disable = fake_set_int; self->set_tx_eq = fake_set_int; self->set_rx_am = fake_set_int; self->set_rx_em = fake_set_int; return 0; default: break; } SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); return ERR_TRANSVR_UNEXCPT; } static int setup_transvr_private_cb(struct transvr_obj_s *self, int transvr_type){ switch (transvr_type){ case TRANSVR_TYPE_SFP: self->init = transvr_init_sfp; self->clean = common_transvr_clean; self->check = common_transvr_check; self->update_all = _sfp_update_attr_all; self->fsm_4_direct = common_fsm_4_direct_mode; self->fsm_4_polling = common_fsm_4_polling_mode; self->send_uevent = sfp_send_uevent; self->dump_all = sfp_transvr_dump; return 0; case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: self->init = transvr_init_qsfp; self->clean = qsfp_transvr_clean; self->check = common_transvr_check; self->update_all = _qsfp_update_attr_all; self->fsm_4_direct = common_fsm_4_direct_mode; self->fsm_4_polling = common_fsm_4_polling_mode; self->send_uevent = qsfp_send_uevent; self->dump_all = qsfp_transvr_dump; return 0; case TRANSVR_TYPE_QSFP_28: self->init = transvr_init_qsfp28; self->clean = qsfp_transvr_clean; self->check = common_transvr_check; self->update_all = _qsfp_update_attr_all; self->fsm_4_direct = common_fsm_4_direct_mode; self->fsm_4_polling = common_fsm_4_polling_mode; self->send_uevent = qsfp_send_uevent; self->dump_all = qsfp_transvr_dump; return 0; case TRANSVR_TYPE_FAKE: self->init = transvr_init_fake; self->clean = fake_transvr_clean; self->check = fake_transvr_check; self->update_all = fake_transvr_update; self->fsm_4_direct = fake_fsm_4_direct_mode; self->fsm_4_polling = fake_fsm_4_polling_mode; self->send_uevent = fake_send_uevent; self->dump_all = fake_transvr_dump; return 0; default: break; } SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); return ERR_TRANSVR_UNEXCPT; } static struct eeprom_map_s * get_eeprom_map(int transvr_type){ switch (transvr_type){ case TRANSVR_TYPE_SFP: return &eeprom_map_sfp; case TRANSVR_TYPE_QSFP: case TRANSVR_TYPE_QSFP_PLUS: return &eeprom_map_qsfp; case TRANSVR_TYPE_QSFP_28: return &eeprom_map_qsfp28; default: break; } SWPS_WARN("%s: Detect non-defined type:%d\n", __func__, transvr_type); return NULL; } static int setup_transvr_ssize_attr(char *swp_name, struct transvr_obj_s *self, struct eeprom_map_s *map_p, struct ioexp_obj_s *ioexp_obj_p, int ioexp_virt_offset, int transvr_type, int chipset_type, int chan_id, int run_mode){ switch (run_mode){ case TRANSVR_MODE_DIRECT: /* Direct access device mode */ case TRANSVR_MODE_POLLING: /* Polling mode, read from cache */ self->mode = run_mode; break; default: SWPS_ERR("%s: non-defined run_mode:%d\n", __func__, run_mode); self->mode = DEBUG_TRANSVR_INT_VAL; return -1; } self->eeprom_map_p = map_p; self->ioexp_obj_p = ioexp_obj_p; self->ioexp_virt_offset = ioexp_virt_offset; self->chan_id = chan_id; self->layout = transvr_type; self->type = transvr_type; self->chipset_type = chipset_type; self->state = STATE_TRANSVR_NEW; self->info = STATE_TRANSVR_NEW; self->auto_tx_disable = VAL_TRANSVR_FUNCTION_DISABLE; strncpy(self->swp_name, swp_name, 32); mutex_init(&self->lock); return 0; } static int setup_transvr_dsize_attr(struct transvr_obj_s *self){ char *emsg = DEBUG_TRANSVR_STR_VAL; self->vendor_name = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL); if (!self->vendor_name){ emsg = "vendor_name"; goto err_setup_d_attr; } self->vendor_pn = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL); if (!self->vendor_pn){ emsg = "vendor_pn"; goto err_setup_d_attr; } self->vendor_rev = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL); if (!self->vendor_rev){ emsg = "vendor_rev"; goto err_setup_d_attr; } self->vendor_sn = kzalloc((LEN_TRANSVR_M_STR * sizeof(char)), GFP_KERNEL); if (!self->vendor_sn){ emsg = "vendor_sn"; goto err_setup_d_attr; } self->worker_p = NULL; return 0; err_setup_d_attr: SWPS_ERR("%s: %s kzalloc fail!", __func__, emsg); return ERR_TRANSVR_UNEXCPT; } static int setup_i2c_client(struct transvr_obj_s *self){ struct i2c_adapter *adap = NULL; struct i2c_client *client = NULL; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; adap = i2c_get_adapter(self->chan_id); if(!adap){ snprintf(err_msg, sizeof(err_msg), "can not get adap:%d", self->chan_id); goto err_setup_i2c_client; } client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client){ snprintf(err_msg, sizeof(err_msg), "can not kzalloc client:%d", self->chan_id); goto err_setup_i2c_client; } client->adapter = adap; self->i2c_client_p = client; self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; return 0; err_setup_i2c_client: SWPS_ERR("%s: %s\n", __func__, err_msg); return ERR_TRANSVR_UNEXCPT; } struct transvr_obj_s * create_transvr_obj(char *swp_name, int chan_id, struct ioexp_obj_s *ioexp_obj_p, int ioexp_virt_offset, int transvr_type, int chipset_type, int run_mode){ struct transvr_obj_s *result_p; struct eeprom_map_s *map_p; char err_msg[64] = DEBUG_TRANSVR_STR_VAL; /* Allocate transceiver object */ map_p = get_eeprom_map(transvr_type); if (!map_p){ snprintf(err_msg, sizeof(err_msg), "Invalid transvr_type:%d", transvr_type); goto err_create_transvr_fail; } result_p = kzalloc(sizeof(*result_p), GFP_KERNEL); if (!result_p){ snprintf(err_msg, sizeof(err_msg), "kzalloc fail"); goto err_create_transvr_fail; } /* Prepare static size attributes */ if (setup_transvr_ssize_attr(swp_name, result_p, map_p, ioexp_obj_p, ioexp_virt_offset, transvr_type, chipset_type, chan_id, run_mode) < 0){ goto err_create_transvr_sattr_fail; } /* Prepare dynamic size attributes */ if (setup_transvr_dsize_attr(result_p) < 0){ goto err_create_transvr_dattr_fail; } /* Prepare call back functions of object */ if (setup_transvr_public_cb(result_p, transvr_type) < 0){ goto err_create_transvr_dattr_fail; } /* Prepare call back functions of object */ if (setup_transvr_private_cb(result_p, transvr_type) < 0){ goto err_create_transvr_dattr_fail; } /* Prepare i2c client object */ if (setup_i2c_client(result_p) < 0){ goto err_create_transvr_dattr_fail; } return result_p; err_create_transvr_dattr_fail: kfree(result_p->vendor_sn); kfree(result_p->vendor_rev); kfree(result_p->vendor_pn); kfree(result_p->vendor_name); err_create_transvr_sattr_fail: kfree(result_p); err_create_transvr_fail: SWPS_ERR("%s: %s :%d :%d :%d\n", __func__, err_msg, chan_id, ioexp_virt_offset, transvr_type); return NULL; } static int _reload_transvr_obj(struct transvr_obj_s *self, int new_type){ struct eeprom_map_s *new_map_p; struct eeprom_map_s *old_map_p = self->eeprom_map_p; struct i2c_client *old_i2c_p = self->i2c_client_p; int old_type = self->type; /* Change state to STATE_TRANSVR_INIT */ self->state = STATE_TRANSVR_INIT; self->type = new_type; /* Replace EEPROME map */ new_map_p = get_eeprom_map(new_type); if (!new_map_p){ goto err_private_reload_func_1; } self->eeprom_map_p = new_map_p; /* Reload i2c client */ if (setup_i2c_client(self) < 0){ goto err_private_reload_func_2; } /* Replace call back functions */ if (setup_transvr_public_cb(self, new_type) < 0){ goto err_private_reload_func_3; } if (setup_transvr_private_cb(self, new_type) < 0){ goto err_private_reload_func_3; } kfree(old_i2c_p); return 0; err_private_reload_func_3: SWPS_INFO("%s: init() fail!\n", __func__); kfree(old_i2c_p); self->state = STATE_TRANSVR_UNEXCEPTED; self->type = TRANSVR_TYPE_ERROR; return -2; err_private_reload_func_2: self->eeprom_map_p = old_map_p; self->i2c_client_p = old_i2c_p; err_private_reload_func_1: self->state = STATE_TRANSVR_UNEXCEPTED; self->type = old_type; SWPS_INFO("%s fail! :0x%02x\n", __func__, new_type); return -1; } static int reload_transvr_obj(struct transvr_obj_s *self, int new_type){ int result_val = ERR_TRANSVR_UNEXCPT; /* Reload phase */ result_val = _reload_transvr_obj(self, new_type); if (result_val < 0){ SWPS_INFO("%s: reload phase fail! :%d\n", __func__, result_val); return EVENT_TRANSVR_RELOAD_FAIL; } /* Initial phase */ result_val = _transvr_init_handler(self); if (result_val < 0){ SWPS_INFO("%s: initial phase fail! :%d\n", __func__, result_val); } return result_val; } int isolate_transvr_obj(struct transvr_obj_s *self) { self->state = STATE_TRANSVR_ISOLATED; SWPS_INFO("%s: %s be isolated\n", __func__, self->swp_name); return 0; } int resync_channel_tier_2(struct transvr_obj_s *self) { int val = TRANSVR_TYPE_ERROR; if (self->state == STATE_TRANSVR_ISOLATED) { return 0; } self->i2c_client_p->addr = VAL_TRANSVR_COMID_ARREESS; val = i2c_smbus_read_byte_data(self->i2c_client_p, VAL_TRANSVR_COMID_OFFSET); if (val < 0) { return -1; } return 0; } /* ----------------------------------------- * ToDo List * ----------------------------------------- * 1. _sfp_detect_class_by_feature() * => Need check ACC use case. * 2. _sfp_detect_class_by_1g_ethernet() * => Need check 0.1G use case. * 3. Loopback transceiver use case. * => Less much data * 4. _qsfp_detect_class_by_extend_comp() * => Verify 100G CWDM4 * => Verify Obsolete (assigned before 100G CWDM4 MSA required FEC) * => Verify 100G CLR4 * => Verify 100GE-DWDM2 * => Verify 40G PSM4 Parallel SMF * => Verify 100G ACC (Active Copper Cable) or 25GAUI C2M ACC. * => Verify 100G ACC or 25GAUI C2M ACC. * => Verify 25GBASE-LR * => Verify 40G Active Cable (XLPPI) */