7f10b6bc35
Why I did it Support Intel Tofino based platforms Netberg Aurora 610 ASIC: Intel Tofino BFN-T10-032D-020 Pors: 48x 25G + 8x 100G How I did it Added specification to device/netberg directory Added platform/barefoot/sonic-platform-modules-netberg contains kernel modules, scripts and sonic_platform packages. Modified the platform/barefoot/one-image.mk and platform/barefoot/rule.mk to include Aurora 610 related ID and files. How to verify it Build SONiC Install the image on the device and verify the related components are installed and shown correctly.
8463 lines
280 KiB
C
8463 lines
280 KiB
C
#include <linux/slab.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/kobject.h>
|
|
#include <linux/delay.h>
|
|
#include "io_expander.h"
|
|
#include "transceiver.h"
|
|
|
|
extern int io_no_init;
|
|
|
|
/* For build single module using (Ex: ONL platform) */
|
|
#include <linux/module.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);
|
|
}
|
|
EXPORT_SYMBOL(alarm_msg_2_user);
|
|
|
|
/* ========== 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);
|
|
|
|
#define I2C_BLOCK_READ_ENABLE
|
|
#define I2C_RETRY_COUNT (3)
|
|
#define I2C_RETRY_DELAY_MS (10)
|
|
static int net_i2c_smbus_read_block_data(struct i2c_client *client, u8 offset, int len, u8 *buf)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
|
|
for (i = 0; i < I2C_RETRY_COUNT; i++) {
|
|
// Notes: The maximum length of the block read is 32 bytes.
|
|
// If the data size is greater than 32 bytes, please divided into multiple reads.
|
|
ret = i2c_smbus_read_i2c_block_data(client, offset, len, buf);
|
|
if (ret < 0) {
|
|
msleep(I2C_RETRY_DELAY_MS);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (i >= I2C_RETRY_COUNT) {
|
|
SWPS_ERR("%s fail:offset:0x%x try %d/%d! Error Code: %d\n", __func__, offset, i, I2C_RETRY_COUNT, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int net_i2c_smbus_read_byte_data(struct i2c_client *client, u8 offset)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
|
|
for (i = 0; i < I2C_RETRY_COUNT; i++) {
|
|
ret = i2c_smbus_read_byte_data(client, offset);
|
|
if (ret < 0) {
|
|
msleep(I2C_RETRY_DELAY_MS);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (i >= I2C_RETRY_COUNT) {
|
|
SWPS_ERR("%s fail:offset:0x%x try %d/%d! Error Code: %d\n", __func__, offset, i, I2C_RETRY_COUNT, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
lock_transvr_obj(struct transvr_obj_s *self) {
|
|
|
|
mutex_lock(&self->lock);
|
|
self->curr_page = VAL_TRANSVR_PAGE_FREE;
|
|
}
|
|
EXPORT_SYMBOL(lock_transvr_obj);
|
|
|
|
|
|
void
|
|
unlock_transvr_obj(struct transvr_obj_s *self) {
|
|
|
|
self->curr_page = VAL_TRANSVR_PAGE_FREE;
|
|
mutex_unlock(&self->lock);
|
|
}
|
|
EXPORT_SYMBOL(unlock_transvr_obj);
|
|
|
|
|
|
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: <addr>:0x%02x <page>:%d <offs>:%d <len>:%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 <err>:%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; i<len; i++) {
|
|
err = net_i2c_smbus_read_byte_data(self->i2c_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 <caller>:%s <err>:%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; i<len; i++) {
|
|
err = i2c_smbus_read_byte_data(self->i2c_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 <caller>:%s <err>:%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 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;
|
|
}
|
|
#ifndef I2C_BLOCK_READ_ENABLE
|
|
int i;
|
|
for (i=0; i<len; i++) {
|
|
err = i2c_smbus_read_byte_data(self->i2c_client_p, (offset + i));
|
|
if (err < 0){
|
|
emsg = "I2C R/W fail!";
|
|
goto err_common_update_string_attr;
|
|
}
|
|
buf[i] = (char)err;
|
|
}
|
|
#else
|
|
err = net_i2c_smbus_read_block_data(self->i2c_client_p, offset, len, buf);
|
|
if (err < 0){
|
|
emsg = "I2C R/W fail!";
|
|
goto err_common_update_string_attr;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
err_common_update_string_attr:
|
|
if (show_e) {
|
|
SWPS_INFO("%s: %s <caller>:%s <err>:%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 <caller>:%s <err>:%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; i<len; i++) {
|
|
if (buf[i] == update[i]){
|
|
continue;
|
|
}
|
|
err = i2c_smbus_write_byte_data(self->i2c_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 <caller>:%s <err>:%d <i>:%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 <swp>:%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 <swp>:%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 <swp>:%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; i<ARRAY_SIZE(self->lane_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[1],
|
|
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
|
|
sfp_get_1g_rj45_extphy_offset(struct transvr_obj_s *self, char *buf) {
|
|
|
|
if (self->state != STATE_TRANSVR_CONNECTED) {
|
|
return ERR_TRANSVR_UNPLUGGED;
|
|
}
|
|
if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
|
|
(self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
|
|
return ERR_TRANSVR_NOTSUPPORT;
|
|
}
|
|
return snprintf(buf, LEN_TRANSVR_S_STR, "0x%02x\n", self->extphy_offset);
|
|
}
|
|
|
|
|
|
int
|
|
sfp_get_1g_rj45_extphy_reg(struct transvr_obj_s *self, char *buf) {
|
|
|
|
int i = 0;
|
|
int ret = 0;
|
|
int retry = 3;
|
|
int delay = 200;
|
|
|
|
if (self->state != STATE_TRANSVR_CONNECTED) {
|
|
return ERR_TRANSVR_UNPLUGGED;
|
|
}
|
|
if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
|
|
(self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
|
|
return ERR_TRANSVR_NOTSUPPORT;
|
|
}
|
|
if (_common_setup_page(self, VAL_TRANSVR_EXTPHY_ADDR_56,
|
|
-1, self->extphy_offset, 1, 0) < 0) {
|
|
return -EIO;
|
|
}
|
|
for (i=0; i<retry; i++) {
|
|
ret = i2c_smbus_read_word_data(self->i2c_client_p, self->extphy_offset);
|
|
if (ret >=0) {
|
|
goto ok_sfp_get_1g_rj45_extphy_reg;
|
|
}
|
|
msleep(delay);
|
|
}
|
|
SWPS_INFO("%s: retry:%d fail <port>:%s <offset>:0x%02x\n",
|
|
__func__, retry, self->swp_name, self->extphy_offset);
|
|
return -EIO;
|
|
|
|
ok_sfp_get_1g_rj45_extphy_reg:
|
|
ret = ((ret & 0x00ff) << 8) | ((ret & 0xff00) >> 8);
|
|
return snprintf(buf, LEN_TRANSVR_S_STR, "0x%04x\n", ret);
|
|
}
|
|
|
|
|
|
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 <ERR>:%d <Port>:%s\n <Input>:%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 <ERR>:%d <Port>:%s\n <Input>:%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 <input>:%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; i<retry; i++) {
|
|
if (__sfp_set_tx_eq(self, input, show_e) < 0){
|
|
continue;
|
|
}
|
|
tmp = self->tx_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 <err>:%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 <input>:%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; i<retry; i++) {
|
|
if (__sfp_set_rx_em(self, input, show_e) < 0){
|
|
continue;
|
|
}
|
|
tmp = self->rx_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 <err>:%d\n", __func__, err);
|
|
return err;
|
|
}
|
|
return _sfp_set_rx_em(self, input, 1);
|
|
}
|
|
|
|
|
|
int
|
|
sfp_set_1g_rj45_extphy_offset(struct transvr_obj_s *self,
|
|
int input) {
|
|
|
|
if (self->state != STATE_TRANSVR_CONNECTED) {
|
|
return ERR_TRANSVR_UNPLUGGED;
|
|
}
|
|
if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
|
|
(self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
|
|
return ERR_TRANSVR_NOTSUPPORT;
|
|
}
|
|
if ((input < 0) || (input > 0xff)) {
|
|
return ERR_TRANSVR_BADINPUT;
|
|
}
|
|
self->extphy_offset = (uint8_t)input;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
sfp_set_1g_rj45_extphy_reg(struct transvr_obj_s *self,
|
|
int input) {
|
|
|
|
int i = 0;
|
|
int retry = 3;
|
|
int delay = 200;
|
|
uint16_t tmp = 0;
|
|
|
|
if (self->state != STATE_TRANSVR_CONNECTED) {
|
|
return ERR_TRANSVR_UNPLUGGED;
|
|
}
|
|
if ((self->info != TRANSVR_CLASS_BASE_T_1000) &&
|
|
(self->info != TRANSVR_CLASS_BASE_T_1000_up) ){
|
|
return ERR_TRANSVR_NOTSUPPORT;
|
|
}
|
|
if ((input < 0) || (input > 0xffff)) {
|
|
return ERR_TRANSVR_BADINPUT;
|
|
}
|
|
tmp = ((input & 0x00ff) << 8) | ((input & 0xff00) >> 8);
|
|
if (_common_setup_page(self, VAL_TRANSVR_EXTPHY_ADDR_56,
|
|
-1, self->extphy_offset, 1, 0) < 0) {
|
|
return -EIO;
|
|
}
|
|
for (i=0; i<=retry; i++) {
|
|
if (i2c_smbus_write_word_data(self->i2c_client_p,
|
|
self->extphy_offset,
|
|
tmp) >= 0) {
|
|
return 0;
|
|
}
|
|
msleep(delay);
|
|
}
|
|
SWPS_INFO("%s: retry:%d fail <port>:%s <offset>:0x%02x\n",
|
|
__func__, retry, self->swp_name, self->extphy_offset);
|
|
return -EIO;
|
|
}
|
|
|
|
|
|
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 <ERR>:%d <Port>:%s\n <Input>:%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 <port>:%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 <port>:%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! <port>:%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 <err>:%d <port>:%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 <port>:%s <input>:%d\n <ret>:%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<CH-1><CH-2><CH-3><CH-4>
|
|
*/
|
|
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 <input>:%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; i<retry; i++) {
|
|
if (__qsfp_set_tx_eq(self, input, show_e) < 0){
|
|
continue;
|
|
}
|
|
tmp[0] = self->tx_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 <err>:%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<CH-1><CH-2><CH-3><CH-4>
|
|
*/
|
|
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 <input>:%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; i<retry; i++) {
|
|
if (__qsfp_set_rx_am(self, input, show_e) < 0){
|
|
continue;
|
|
}
|
|
tmp[0] = self->rx_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 <err>:%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<CH-1><CH-2><CH-3><CH-4>
|
|
*/
|
|
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 <input>:%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; i<retry; i++) {
|
|
if (__qsfp_set_rx_em(self, input, show_e) < 0){
|
|
continue;
|
|
}
|
|
tmp[0] = self->rx_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 <err>:%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 " |- <Type>:%s\n", type_name);
|
|
printk(KERN_INFO " |- <VenderName>:%s\n", self->vendor_name);
|
|
printk(KERN_INFO " |- <VenderPN>:%s\n", self->vendor_pn);
|
|
printk(KERN_INFO " |- <VenderREV>:%s\n", self->vendor_rev);
|
|
printk(KERN_INFO " |- <VenderSN>:%s\n", self->vendor_sn);
|
|
printk(KERN_INFO " |- <BitRate>:0x%02x\n", self->br);
|
|
printk(KERN_INFO " |- <RevComp>:0x%02x\n", self->comp_rev);
|
|
printk(KERN_INFO " |- <LenOM1>:%d\n", self->len_om1);
|
|
printk(KERN_INFO " |- <LenOM2>:%d\n", self->len_om2);
|
|
printk(KERN_INFO " |- <LenOM3>:%d\n", self->len_om3);
|
|
printk(KERN_INFO " |- <LenOM4>:%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 " |- <LenSM>:%d\n", self->len_sm);
|
|
printk(KERN_INFO " |- <LenSMF>:%d\n", self->len_smf);
|
|
printk(KERN_INFO " '- <RateID>: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 " |- <LenSMF>:%d\n", self->len_smf);
|
|
printk(KERN_INFO " '- <PowerClass>: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 " |- <Type>:FAKE\n");
|
|
printk(KERN_INFO " |- <VenderName>:FAKE_VENDER_NAME\n");
|
|
printk(KERN_INFO " |- <VenderPN>:FAKE_VENDER_PN\n");
|
|
printk(KERN_INFO " |- <VenderREV>:FAKE_VENDER_REV\n");
|
|
printk(KERN_INFO " |- <VenderSN>:FAKE_VENDER_SN\n");
|
|
printk(KERN_INFO " |- <BitRate>:0x99\n");
|
|
printk(KERN_INFO " |- <LenOM1>:99\n");
|
|
printk(KERN_INFO " |- <LenOM2>:99\n");
|
|
printk(KERN_INFO " |- <LenOM3>:99\n");
|
|
printk(KERN_INFO " |- <LenOM4>:99\n");
|
|
printk(KERN_INFO " |- <LenSM>:99\n");
|
|
printk(KERN_INFO " |- <LenSMF>:99\n");
|
|
printk(KERN_INFO " '- <RevComp>: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 <caller>:%s <port>:%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 <port>:%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 void
|
|
transvr_cache_free_all(struct transvr_obj_s *self) {
|
|
|
|
memset(self->vendor_name, 0, (LEN_TRANSVR_M_STR * sizeof(char)) );
|
|
memset(self->vendor_rev, 0, (LEN_TRANSVR_M_STR * sizeof(char)) );
|
|
memset(self->vendor_pn, 0, (LEN_TRANSVR_M_STR * sizeof(char)) );
|
|
memset(self->vendor_sn, 0, (LEN_TRANSVR_M_STR * sizeof(char)) );
|
|
self->extphy_offset = 0;
|
|
}
|
|
|
|
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 <rval>:%d <port>:%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 <state>:%d <port>:%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 <main>:%d <post>:%d <caller>:%s <port>:%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 <port>:%s <input>:%d <err>:%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 <port>:%s <input>:%d <err>:%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 <port>:%s <input>:%d <err>:%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 <port>:%s <input>:%d <err>:%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 <port>:%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;
|
|
if (io_no_init) {
|
|
|
|
SWPS_INFO("%s no_io_init\n",__func__);
|
|
return EVENT_TRANSVR_TASK_DONE;
|
|
}
|
|
|
|
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 <err>:%d <curr>:%d <input>:%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; i<retry; i++) {
|
|
if (_qsfp_set_auto_tx_disable(task_p->transvr_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 <err>:%d <port>:%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 <port>:%s <type>: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 <port>:%s <type>:0x%02x, <err>:%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 <port>:%s <type>:%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 <ERR>:%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 <ERR>:%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 <port>:%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 <err>:%d <port>:%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! <pres>:%d <istate>:%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 <NEW_TYPE>/<OLD_TYPE>
|
|
* 0 STATE_TRANSVR_SWAPPED <NEW_TYPE>
|
|
* 0 STATE_TRANSVR_CONNECTED <OLD_TYPE>
|
|
* ERR_TRNASVR_BE_ISOLATED STATE_TRANSVR_ISOLATED TRANSVR_TYPE_ERROR <Isolated>
|
|
* ERR_TRANSVR_I2C_CRASH STATE_TRANSVR_UNEXCEPTED TRANSVR_TYPE_ERROR <New event>
|
|
* 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 <obj-state>:%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 <port>:%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 <port>:%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 <port>:%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 <port>:%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 <port>:%s\n", __func__, err_msg, self->swp_name);
|
|
return TRANSVR_CLASS_ERROR;
|
|
}
|
|
|
|
|
|
int
|
|
_sfp_set_magnolia_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_magnolia_if_type_1;
|
|
}
|
|
/* Exception case: Can't verify */
|
|
snprintf(err_msg, sizeof(err_msg), "Can not identify!");
|
|
goto err_sfp_set_magnolia_if_type_1;
|
|
|
|
err_sfp_set_magnolia_if_type_1:
|
|
snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
|
|
SWPS_INFO("%s: %s <port>:%s\n", __func__, err_msg, self->swp_name);
|
|
return ERR_TRANSVR_ABNORMAL;
|
|
}
|
|
|
|
|
|
int
|
|
_sfp_set_redwood_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_redwood_if_type_1;
|
|
}
|
|
/* Exception case: Can't verify */
|
|
snprintf(err_msg, sizeof(err_msg), "Can not identify!");
|
|
goto err_sfp_set_redwood_if_type_1;
|
|
|
|
err_sfp_set_redwood_if_type_1:
|
|
snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
|
|
SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
|
|
return ERR_TRANSVR_ABNORMAL;
|
|
}
|
|
|
|
|
|
int
|
|
_sfp_set_lavender_if_type(struct transvr_obj_s* self,
|
|
int transvr_cls,
|
|
char *result) {
|
|
/* (TBD)
|
|
* Due to 'LAV' looks like doesn't have interface type.
|
|
* We bypass it currently.
|
|
*/
|
|
int lmax = 8;
|
|
return snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
|
|
}
|
|
|
|
|
|
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 CHIP_TYPE_MAGNOLIA:
|
|
return _sfp_set_magnolia_if_type(self, detect_cls, result);
|
|
|
|
case CHIP_TYPE_MAPLE:
|
|
case CHIP_TYPE_REDWOOD:
|
|
return _sfp_set_redwood_if_type(self, detect_cls, result);
|
|
|
|
case CHIP_TYPE_LAVENDER:
|
|
return _sfp_set_lavender_if_type(self, detect_cls, result);
|
|
|
|
default:
|
|
SWPS_INFO("%s: non-defined chipset_type:%d <port>:%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 <port>:%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 <port>:%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 <port>:%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 <port>:%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 <port>:%s", __func__, err_msg, self->swp_name);
|
|
return TRANSVR_CLASS_ERROR;
|
|
}
|
|
|
|
|
|
int
|
|
_qsfp_set_magnolia_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_magnolia_if_type_1;
|
|
}
|
|
/* Exception case: Can't verify */
|
|
snprintf(err_msg, sizeof(err_msg), "Can not identify!");
|
|
goto err_qsfp_set_magnolia_if_type_1;
|
|
|
|
err_qsfp_set_magnolia_if_type_1:
|
|
snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
|
|
SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
|
|
return ERR_TRANSVR_ABNORMAL;
|
|
}
|
|
|
|
|
|
int
|
|
_qsfp_set_redwood_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_magnolia_if_type_1;
|
|
}
|
|
/* Exception case: Can't verify */
|
|
snprintf(err_msg, sizeof(err_msg), "Can not identify!");
|
|
goto err_qsfp_set_magnolia_if_type_1;
|
|
|
|
err_qsfp_set_magnolia_if_type_1:
|
|
snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
|
|
SWPS_INFO("%s: %s\n <port>:%s", __func__, err_msg, self->swp_name);
|
|
return ERR_TRANSVR_ABNORMAL;
|
|
}
|
|
|
|
|
|
int
|
|
_qsfp_set_lavender_if_type(struct transvr_obj_s* self,
|
|
int transvr_cls,
|
|
char *result) {
|
|
/* (TBD)
|
|
* Due to 'LAV' looks like doesn't have interface type.
|
|
* We bypass it currently.
|
|
*/
|
|
int lmax = 8;
|
|
return snprintf(result, lmax, TRANSVR_UEVENT_UNKNOW);
|
|
}
|
|
|
|
|
|
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 CHIP_TYPE_MAGNOLIA:
|
|
return _qsfp_set_magnolia_if_type(self, detect_cls, result);
|
|
|
|
case CHIP_TYPE_MAPLE:
|
|
case CHIP_TYPE_REDWOOD:
|
|
return _qsfp_set_redwood_if_type(self, detect_cls, result);
|
|
|
|
case CHIP_TYPE_LAVENDER:
|
|
return _qsfp_set_lavender_if_type(self, detect_cls, result);
|
|
|
|
default:
|
|
SWPS_INFO("%s: non-defined chipset_type:%d <port>:%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 <port>:%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; i<ARRAY_SIZE(self->lane_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 <port>:%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 -> <ANY> */
|
|
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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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. <case>: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: <os>:%d <ot>:0x%02x <ns>:%d <nt>: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 <err>:%d <port>:%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 <err>:%d <port>:%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 <err>:%d <port>:%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<<bit)) == ready) {
|
|
return EVENT_TRANSVR_TASK_DONE;
|
|
}
|
|
return EVENT_TRANSVR_TASK_WAIT;
|
|
|
|
bypass_is_transvr_hw_ready:
|
|
SWPS_DEBUG("%s: %s <type>:%d\n", __func__, emsg, type);
|
|
return EVENT_TRANSVR_TASK_DONE;
|
|
|
|
err_is_transvr_hw_ready:
|
|
SWPS_DEBUG("%s: %s <type>:%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 <port>:%s <case>: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 <port>:%s <case>: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 <port>:%s <case>: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 <port>:%s\n", __func__, emsg, self->swp_name);
|
|
SWPS_INFO("Dump: <os>:%d <ot>:%d <ns>:%d <nt>:%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 <port>:%s <case>: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);
|
|
transvr_cache_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! <err>:%d\n",
|
|
__func__, retval);
|
|
return retval;
|
|
}
|
|
retval = common_transvr_clean(self);
|
|
if (retval < 0){
|
|
SWPS_ERR("%s: common_transvr_clean fail! <err>:%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->get_extphy_offset = sfp_get_1g_rj45_extphy_offset;
|
|
self->get_extphy_reg = sfp_get_1g_rj45_extphy_reg;
|
|
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;
|
|
self->set_extphy_offset = sfp_set_1g_rj45_extphy_offset;
|
|
self->set_extphy_reg = sfp_set_1g_rj45_extphy_reg;
|
|
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->get_extphy_offset = unsupported_get_func2;
|
|
self->get_extphy_reg = unsupported_get_func2;
|
|
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;
|
|
self->set_extphy_offset = unsupported_set_func;
|
|
self->set_extphy_reg = 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->get_extphy_offset = unsupported_get_func2;
|
|
self->get_extphy_reg = unsupported_get_func2;
|
|
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;
|
|
self->set_extphy_offset = unsupported_set_func;
|
|
self->set_extphy_reg = unsupported_set_func;
|
|
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->get_extphy_offset = fake_get_str;
|
|
self->get_extphy_reg = 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;
|
|
self->set_extphy_offset = fake_set_hex;
|
|
self->set_extphy_reg = fake_set_hex;
|
|
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 <chan>:%d <voff>:%d <type>:%d\n",
|
|
__func__, err_msg, chan_id, ioexp_virt_offset, transvr_type);
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL(create_transvr_obj);
|
|
|
|
|
|
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;
|
|
}
|
|
if(old_i2c_p){
|
|
i2c_put_adapter(old_i2c_p->adapter);
|
|
}
|
|
kfree(old_i2c_p);
|
|
return 0;
|
|
|
|
err_private_reload_func_3:
|
|
SWPS_INFO("%s: init() fail!\n", __func__);
|
|
if(old_i2c_p){
|
|
i2c_put_adapter(old_i2c_p->adapter);
|
|
}
|
|
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! <type>: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! <err>:%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! <err>:%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;
|
|
}
|
|
EXPORT_SYMBOL(isolate_transvr_obj);
|
|
|
|
|
|
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;
|
|
}
|
|
EXPORT_SYMBOL(resync_channel_tier_2);
|
|
|
|
/* For build single module using (Ex: ONL platform) */
|
|
MODULE_LICENSE("GPL");
|
|
|
|
|
|
/* -----------------------------------------
|
|
* 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)
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|