Commit dfcea15f authored by Adam Wujek's avatar Adam Wujek 💬

Merge branch 'sfp_diag'

--Read DOM (Diagnostic Monitoring data) data from SFPs
--Fix the write to SFPs eeprom
--store DOM data in the HAL's shmem
Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parents 79f88bdf 579646e4
......@@ -860,7 +860,11 @@ config FAN_HYSTERESIS_PWM_VAL
PWM value used to drive fans. Range from 4 to 1000.
endmenu
config READ_SFP_DIAG_ENABLE
bool "Read SFPs Diagnostic Monitoring"
default n
help
Let HAL to read Diagnostic Monitoring from SFP's eeprom.
endmenu
menu "RTU HP mask"
......
......@@ -834,6 +834,11 @@ value is changed by the web interface, proper action is taken.
below @t{CONFIG_FAN_HYSTERESIS_T_DISABLE}. These options are intended to
be used during development to reduce noise generated by switch.
@item CONFIG_READ_SFP_DIAG_ENABLE
Let HAL to read Diagnostic Monitoring from SFP's eeprom like
temperature, TX/RX power etc.
@item CONFIG_RTU_HP_MASK_ENABLE
@itemx CONFIG_RTU_HP_MASK_VAL
......
......@@ -47,6 +47,9 @@
#define SFP_LED_WRMODE_MASK(t) ((t) ? (1 << 5) : (1 << 3))
#define SFP_TX_DISABLE_MASK(t) ((t) ? (1 << 7) : (1 << 2))
/* Either 8 or 16 byte pages, so we use the smaller */
#define SFP_PAGE_SIZE 8
/*
* We need these tables because the schematics are messed up
* The first one is for figuring out the masks in the pca9548's
......@@ -318,6 +321,15 @@ void shw_sfp_print_header(struct shw_sfp_header *head)
printf("\n");
}
void shw_sfp_print_dom(struct shw_sfp_dom * dom)
{
printf("Temperature: %.3f C\n", (int8_t)dom->temp[0] + dom->temp[1]/(float)256);
printf("Voltage: %.3f V\n", (dom->vcc[0]*256 + dom->vcc[1])/(float)10000);
printf("Bias Current: %.3f uA\n", (dom->tx_bias[0]*256+dom->tx_bias[1])/(float)500000);
printf("TX power: %.3f mW\n", (dom->tx_pow[0]*256 + dom->tx_pow[1])/(float)100000);
printf("RX power: %.3f mW\n", (dom->rx_pow[0]*256 + dom->rx_pow[1])/(float)100000);
}
void shw_sfp_header_dump(struct shw_sfp_header *head)
{
int i;
......@@ -332,6 +344,20 @@ void shw_sfp_header_dump(struct shw_sfp_header *head)
}
void shw_sfp_dom_dump(struct shw_sfp_dom *dom)
{
int i;
uint8_t *dump = (uint8_t *) dom;
printf("Dom Dump:");
for (i = 0; i < sizeof(struct shw_sfp_dom); i++) {
if (i % 8 == 0)
printf("\n");
printf("%02X ", dump[i]);
}
printf("\n");
}
/* Get the SFP ID from the SFP number (0 to 17) */
inline int shw_sfp_id(int num)
{
......@@ -369,15 +395,26 @@ int32_t shw_sfp_read(int num, uint32_t addr, int off, int len, uint8_t * buf)
return i2c_transfer(bus, addr, 0, len, buf);
}
int32_t shw_sfp_write(int num, uint32_t addr, int off, int len, uint8_t * buf)
{
int id;
uint8_t byte1, byte2;
int32_t counter = 0;
struct i2c_bus *bus;
int i = 0;
uint8_t page[SFP_PAGE_SIZE + 1];
int ret;
/* The SFP eeprom only supports 8 bit addresses */
if (len < 1 || len > 256 || off < 0 || off > 256 || off + len < 0
|| off + len > 256)
return -1;
id = shw_sfp_id(num);
if (id < 0)
return -1;
bus = &i2c_buses[WR_MUX_BUS];
if (id == 0 || id == 1)
bus = &i2c_buses[WR_SFP0_BUS + id];
......@@ -390,11 +427,44 @@ int32_t shw_sfp_write(int num, uint32_t addr, int off, int len, uint8_t * buf)
i2c_transfer(bus, 0x71, 1, 0, &byte2);
}
/* Send the offset we want to write to if requested */
if (off >= 0)
i2c_transfer(bus, addr, 1, 0, (uint8_t *) & off);
/* Do the read */
return i2c_transfer(bus, addr, len, 0, buf);
/* Write in a paged mode, 1 byte address */
page[0] = (counter + off) & 0xff;
while (counter < len)
{
page[i + 1] = buf[counter++];
i++;
/* When we hit a page boundary then perform a write */
if ((off + counter) % SFP_PAGE_SIZE == 0)
{
pr_debug("Writing %d bytes to EEPROM address %02x\n",
i, page[0]);
ret = i2c_transfer(bus, addr, i + 1, 0, page);
if (ret < 0) {
pr_error("i2c_transfer error code 0x%x\n",
ret);
return -1;
}
i = 0;
page[0] = (counter + off) & 0xff;
/* Sleep 10ms for eeprom to finish writing the page */
/* XXX this should actually be done by polling the */
/* EEPROM and seeing if it is ready */
usleep(10000);
}
}
/* Write the last page, if not already done */
if (i != 0)
{
pr_debug("Writing last %d bytes to EEPROM address %02x\n",
i, page[0]);
ret = i2c_transfer(bus, addr, i + 1, 0, page);
if (ret < 0) {
pr_error("i2c_transfer error code 0x%x\n", ret);
return -1;
}
usleep(10000);
}
return counter;
}
uint32_t shw_sfp_module_scan(void)
......@@ -559,6 +629,39 @@ int shw_sfp_read_header(int num, struct shw_sfp_header *head)
return 0;
}
int shw_sfp_read_dom(int num, struct shw_sfp_dom *dom)
{
int ret;
if (shw_sfp_id(num) < 0) {
pr_error("shw_sfp_read_header: wrong SFP num %d\n", num + 1);
return -1;
}
ret = shw_sfp_module_scan();
if (!(ret & (1 << num))) {
pr_error("shw_sfp_read_header: SFP not present %d\n", num + 1);
return -2;
}
ret =
shw_sfp_read(num, I2C_SFP_DOM_ADDRESS, 0x0,
sizeof(struct shw_sfp_dom), (uint8_t *) dom);
if (ret == I2C_DEV_NOT_FOUND) {
pr_error("shw_sfp_read_header: I2C_DEV_NOT_FOUND\n");
return -ENODEV;
}
return 0;
}
/* Function to update SFP's Diagnostic Monitoring data from SFP's eeprom */
int shw_sfp_update_dom(int num, struct shw_sfp_dom *dom)
{
/* For now copy entire eeprom */
return shw_sfp_read_dom(num, dom);
}
int shw_sfp_read_verify_header(int num, struct shw_sfp_header *head)
{
int ret;
......
......@@ -7,6 +7,8 @@
//address from AT24C01 datasheet (1k, all address lines shorted to the ground)
#define I2C_SFP_ADDRESS 0x50
// From SFF-8472, but right-shifted one bit as I2C addresses are only 7 bits.
#define I2C_SFP_DOM_ADDRESS 0x51
/* The two FPGA buses */
#define WR_FPGA_BUS0 0
......
......@@ -12,6 +12,10 @@
#define HAL_PORT_STATE_CALIBRATION 3
#define HAL_PORT_STATE_LOCKING 4
/* Read temperature from SFPs */
#define READ_SFP_DIAG_ENABLE 1
#define READ_SFP_DIAG_DISABLE 0
#define DEFAULT_T2_PHASE_TRANS 0
#define DEFAULT_T4_PHASE_TRANS 0
......@@ -46,6 +50,7 @@ typedef struct hal_port_calibration {
struct shw_sfp_caldata sfp;
struct shw_sfp_header sfp_header_raw;
struct shw_sfp_dom sfp_dom_raw;
} hal_port_calibration_t;
/* Internal port state structure */
......@@ -100,6 +105,9 @@ struct hal_port_state {
/* Endpoint's base address */
uint32_t ep_base;
/* whether SFP has diagnostic Monitoring capability */
int has_sfp_diag;
};
struct hal_temp_sensors {
......@@ -110,13 +118,15 @@ struct hal_temp_sensors {
};
/* This is the overall structure stored in shared memory */
#define HAL_SHMEM_VERSION 9 /* Version 9 because of adding sfp_header_raw */
#define HAL_SHMEM_VERSION 10 /* Version 10 because of adding sfp_dom_raw
has_sfp_diag and read_sfp_diag */
struct hal_shmem_header {
int nports;
int hal_mode;
struct hal_port_state *ports;
struct hal_temp_sensors temp;
int read_sfp_diag;
};
static inline int state_up(int state)
......
......@@ -30,6 +30,16 @@
#define SFP_SPEED_1Gb_10 0x0A /* Unfortunatelly the above is not always true,
* e.g. Cisco copper SFP (MGBT1) says simply 10 and not 13.*/
#define SFP_DIAGNOSTIC_IMPLEMENTED (1 << 6) /* Digital diagnostic monitoring
implemented. "1" for compliance
with SFF-8472 */
#define SFP_ADDR_CHANGE_REQ (1 << 2) /* Bit 2 indicates whether or not it is
necessary for the host to perform an
address change sequence before
accessing information at 2-wire serial
address A2h. */
struct shw_sfp_caldata {
uint32_t flags;
/*
......@@ -64,9 +74,9 @@ struct shw_sfp_header {
uint8_t length3; /* Link length supported for 50/125 mm fiber (10m) */
uint8_t length4; /* Link length supported for 62.5/125 mm fiber (10m) */
uint8_t length5; /* Link length supported for copper (1m) */
uint8_t reserved2;
uint8_t length6; /* Link length supported on OM3 (1m) */
uint8_t vendor_name[16];
uint8_t reserved3;
uint8_t reserved3; /* This is now a field named transceiver */
uint8_t vendor_oui[3];
uint8_t vendor_pn[16];
uint8_t vendor_rev[4];
......@@ -80,10 +90,73 @@ struct shw_sfp_header {
uint8_t br_min;
uint8_t vendor_serial[16];
uint8_t date_code[8];
uint8_t reserved[3];
uint8_t diagnostic_monitoring_type;
uint8_t enhanced_options;
uint8_t sff_8472_compliance;
uint8_t cc_ext;
} __attribute__ ((packed));
struct shw_sfp_dom {
/* Treshold values, 0 - 55 */
uint8_t temp_high_alarm[2];
uint8_t temp_low_alarm[2];
uint8_t temp_high_warn[2];
uint8_t temp_low_warn[2];
uint8_t volt_high_alarm[2];
uint8_t volt_low_alarm[2];
uint8_t volt_high_warn[2];
uint8_t volt_low_warn[2];
uint8_t bias_high_alarm[2];
uint8_t bias_low_alarm[2];
uint8_t bias_high_warn[2];
uint8_t bias_low_warn[2];
uint8_t tx_pow_high_alarm[2];
uint8_t tx_pow_low_alarm[2];
uint8_t tx_pow_high_warn[2];
uint8_t tx_pow_low_warn[2];
uint8_t rx_pow_high_alarm[2];
uint8_t rx_pow_log_alarm[2];
uint8_t rx_power_high_warn[2];
uint8_t rx_power_low_warn[2];
uint8_t unalloc0[16];
/* Calibration data, 56-91 */
uint8_t cal_rx_pwr4[4];
uint8_t cal_rx_pwr3[4];
uint8_t cal_rx_pwr2[4];
uint8_t cal_rx_pwr1[4];
uint8_t cal_rx_pwr0[4];
uint8_t cal_tx_i_slope[2];
uint8_t cal_tx_i_offset[2];
uint8_t cal_tx_pow_slope[2];
uint8_t cal_tx_pow_offset[2];
uint8_t cal_T_slope[2];
uint8_t cal_T_offset[2];
uint8_t cal_V_slope[2];
uint8_t cal_V_offset[2];
/* Unallocated and checksum, 92-95 */
uint8_t cal_unalloc[3];
uint8_t CC_DMI;
/* Real Time Diagnostics, 96-111 */
uint8_t temp[2];
uint8_t vcc[2];
uint8_t tx_bias[2];
uint8_t tx_pow[2];
uint8_t rx_pow[2];
uint8_t rtd_unalloc0[4];
uint8_t OSCB;
uint8_t rtd_unalloc1;
/* Alarms and Warnings, 112 - 117 */
uint8_t alw[6];
/* Extended Module Control/Status bytes 118 - 119 */
uint8_t emcsb[2];
/* Vendor locations 120 - 127 */
uint8_t vendor_locations[8];
/* User data 128 - 247 */
uint8_t dom_user[120];
/* Vendor specific control function locations 248 - 255 */
uint8_t vendor_functions[8];
} __attribute__ ((packed));
/* Public API */
/*
......@@ -113,6 +186,18 @@ int shw_sfp_read_db(void);
/* Read and verify the header all at once. returns -1 on failure */
int shw_sfp_read_verify_header(int num, struct shw_sfp_header *head);
/* Read the SFP diagnostics page */
int shw_sfp_read_dom(int num, struct shw_sfp_dom *dom);
/* Update the SFP diagnostics page */
int shw_sfp_update_dom(int num, struct shw_sfp_dom *dom);
/* Decode and print the SFP real time diagnostics */
void shw_sfp_print_dom(struct shw_sfp_dom * dom);
/* Dump the SFP diagnostics page in hex */
void shw_sfp_dom_dump(struct shw_sfp_dom * dom);
/* return NULL if no data found */
struct shw_sfp_caldata *shw_sfp_get_cal_data(int num,
struct shw_sfp_header *head);
......
ppsi @ 6f9508cf
Subproject commit 3ece12b3824d42910145fe0fa622d00cac1597ef
Subproject commit 6f9508cfb22a78f00fab8db6ff2e6c84441dcb3a
......@@ -382,6 +382,7 @@ void dump_many_fields(void *addr, struct dump_info *info, int ninfo)
struct dump_info hal_shmem_info [] = {
DUMP_FIELD(int, nports),
DUMP_FIELD(int, hal_mode),
DUMP_FIELD(int, read_sfp_diag),
DUMP_FIELD(sensor_temp, temp.fpga),
DUMP_FIELD(sensor_temp, temp.pll),
DUMP_FIELD(sensor_temp, temp.psl),
......@@ -433,6 +434,7 @@ struct dump_info hal_port_info [] = {
DUMP_FIELD(uint32_t, t2_phase_transition),
DUMP_FIELD(uint32_t, t4_phase_transition),
DUMP_FIELD(uint32_t, ep_base),
DUMP_FIELD(int, has_sfp_diag),
};
int dump_hal_mem(struct wrs_shm_head *head)
......
......@@ -33,11 +33,12 @@ void print_info(char *prgname)
"Optional parameters:\n"
" -p <num> Dump sfp header for specific port (1-18); dump sfp header info for all\n"
" ports if no <-p> specified\n"
" -x Dump sfp header also in hex\n"
" -a <READ|WRITE> Read/write SFP's eeprom; works only with <-I>;\n"
" before READs/WRITEs disable HAL and monit!\n"
" -f <file> File to READ/WRITE SFP's eeprom\n"
" -H <dir> Open shmem dumps from the given directory; works only with <-L>\n"
" -d Dump sfp DOM data page\n"
" -x Dump sfp/DOM header also in hex\n"
" -q Decrease verbosity\n"
" -v Increase verbosity\n"
" -V Print version\n"
......@@ -201,7 +202,8 @@ void print_version(char *prgname)
__GIT_USR__);
}
int hal_read(struct shw_sfp_header *sfp_header_local_copy) {
int hal_read(struct shw_sfp_header *sfp_header_local_copy,
struct shw_sfp_dom *sfp_dom) {
unsigned ii;
unsigned retries = 0;
int port;
......@@ -214,7 +216,12 @@ int hal_read(struct shw_sfp_header *sfp_header_local_copy) {
&hal_ports[port].calib.sfp_header_raw,
sizeof(struct shw_sfp_header));
}
if (sfp_dom)
for (port = 0; port < hal_nports_local; port++) {
memcpy(&sfp_dom[port],
&hal_ports[port].calib.sfp_dom_raw,
sizeof(struct shw_sfp_dom));
}
retries++;
if (retries > 100)
return -1;
......@@ -280,23 +287,27 @@ int main(int argc, char **argv)
int c;
struct shw_sfp_header sfp_hdr;
struct shw_sfp_header *sfp_hdr_p;
struct shw_sfp_dom sfp_dom;
struct shw_sfp_dom *sfp_dom_p;
int err;
int nports;
int dump_port;
int i;
int dump_hex_header = 0;
int dump_sfp_dom = 0;
int operation = 0;
char *eeprom_file = NULL;
int sfp_data_source = 0;
/* local copy of sfp eeprom */
struct shw_sfp_header hal_sfp_raw_header_lc[HAL_MAX_PORTS];
struct shw_sfp_dom hal_sfp_raw_dom_lc[HAL_MAX_PORTS];
wrs_msg_init(argc, argv);
nports = 18;
dump_port = 1;
while ((c = getopt(argc, argv, "a:hqvp:xVf:LIH:")) != -1) {
while ((c = getopt(argc, argv, "a:hqvp:xVf:LIdH:")) != -1) {
switch (c) {
case 'p':
dump_port = atoi(optarg);
......@@ -311,6 +322,9 @@ int main(int argc, char **argv)
case 'x':
dump_hex_header = 1;
break;
case 'd':
dump_sfp_dom = 1;
break;
case 'V':
print_version(argv[0]);
exit(0);
......@@ -363,7 +377,7 @@ int main(int argc, char **argv)
if (sfp_data_source == READ_HAL) {
hal_init_shm();
hal_read(hal_sfp_raw_header_lc);
hal_read(hal_sfp_raw_header_lc, hal_sfp_raw_dom_lc);
printf("Reading SFP eeprom from HAL\n");
}
......@@ -392,9 +406,13 @@ int main(int argc, char **argv)
memset(&sfp_hdr, 0, sizeof(sfp_hdr));
sfp_hdr_p = &sfp_hdr;
err = shw_sfp_read_header(i - 1, sfp_hdr_p);
memset(&sfp_dom, 0, sizeof(sfp_dom));
sfp_dom_p = &sfp_dom;
shw_sfp_read_dom(i - 1, sfp_dom_p);
}
if (sfp_data_source == READ_HAL) {
sfp_hdr_p = &hal_sfp_raw_header_lc[i - 1];
sfp_dom_p = &hal_sfp_raw_dom_lc[i - 1];
}
err = shw_sfp_header_verify(sfp_hdr_p);
if (err == -2) {
......@@ -408,6 +426,12 @@ int main(int argc, char **argv)
if (dump_hex_header) {
shw_sfp_header_dump(sfp_hdr_p);
}
if(dump_sfp_dom) {
shw_sfp_print_dom(sfp_dom_p);
if(dump_hex_header) {
shw_sfp_dom_dump(sfp_dom_p);
}
}
}
}
return 0;
......
......@@ -211,6 +211,7 @@ static int hal_port_init(int index)
int hal_port_init_shmem(char *logfilename)
{
int index;
char *ret;
pr_info("Initializing switch ports...\n");
/* default timeouts */
......@@ -255,6 +256,14 @@ int hal_port_init_shmem(char *logfilename)
hal_shmem->nports = hal_port_nports;
hal_shmem_hdr->version = HAL_SHMEM_VERSION;
hal_shmem->hal_mode = hal_get_timing_mode();
ret = libwr_cfg_get("READ_SFP_DIAG_ENABLE");
if (ret && !strcmp(ret, "y")) {
pr_info("Read SFP Diagnostic Monitoring enabled\n");
hal_shmem->read_sfp_diag = READ_SFP_DIAG_ENABLE;
} else
hal_shmem->read_sfp_diag = READ_SFP_DIAG_DISABLE;
/* Release processes waiting for HAL's to fill shm with correct data
When shm is opened successfully data in shm is still not populated!
Read data with wrs_shm_seqbegin and wrs_shm_seqend!
......@@ -478,6 +487,7 @@ static void hal_port_insert_sfp(struct hal_port_state * p)
int err;
memset(&shdr, 0, sizeof(struct shw_sfp_header));
memset(&p->calib.sfp_dom_raw, 0, sizeof(struct shw_sfp_dom));
err = shw_sfp_read_verify_header(p->hw_index, &shdr);
memcpy(&p->calib.sfp_header_raw, &shdr, sizeof(struct shw_sfp_header));
if (err == -2) {
......@@ -489,7 +499,27 @@ static void hal_port_insert_sfp(struct hal_port_state * p)
p->name);
return;
}
if (hal_shmem->read_sfp_diag == READ_SFP_DIAG_ENABLE
&& shdr.diagnostic_monitoring_type & SFP_DIAGNOSTIC_IMPLEMENTED) {
pr_info("SFP Diagnostic Monitoring implemented in SFP plugged"
" to port %d (%s)\n", p->hw_index + 1, p->name);
if (shdr.diagnostic_monitoring_type & SFP_ADDR_CHANGE_REQ) {
pr_warning("SFP in port %d (%s) requires special "
"address change before accessing Diagnostic"
" Monitoring, which is not implemented "
"right now\n", p->hw_index + 1, p->name);
} else {
/* copy coontent of SFP's Diagnostic Monitoring */
shw_sfp_read_dom(p->hw_index, &p->calib.sfp_dom_raw);
if (err < 0) {
pr_error("Failed to read SFP Diagnostic "
"Monitoring for port %d (%s)\n",
p->hw_index + 1, p->name);
}
p->has_sfp_diag = 1;
}
}
pr_info("SFP Info: Manufacturer: %.16s P/N: %.16s, S/N: %.16s\n",
shdr.vendor_name, shdr.vendor_pn, shdr.vendor_serial);
cdata = shw_sfp_get_cal_data(p->hw_index, &shdr);
......@@ -570,6 +600,8 @@ static void hal_port_remove_sfp(struct hal_port_state * p)
/* clean SFP's details when removing SFP */
memset(&p->calib.sfp, 0, sizeof(p->calib.sfp));
memset(&p->calib.sfp_header_raw, 0, sizeof(struct shw_sfp_header));
memset(&p->calib.sfp_dom_raw, 0, sizeof(struct shw_sfp_dom));
p->has_sfp_diag = 0;
}
/* detects insertion/removal of SFP transceivers */
......@@ -615,10 +647,20 @@ void hal_port_update_all()
hal_port_poll_sfp();
for (i = 0; i < HAL_MAX_PORTS; i++)
if (ports[i].in_use)
if (ports[i].in_use) {
hal_port_fsm(&ports[i]);
/* update DOM only for plugged ports with DOM
* capabilities */
if (ports[i].state != HAL_PORT_STATE_DISABLED
&& hal_shmem->read_sfp_diag == READ_SFP_DIAG_ENABLE
&& (ports[i].has_sfp_diag)) {
shw_sfp_update_dom(ports[i].hw_index,
&ports[i].calib.sfp_dom_raw);
}
}
/* unlock shmem */
wrs_shm_write(hal_shmem_hdr, WRS_SHM_WRITE_END);
}
int hal_port_enable_tracking(const char *port_name)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment