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

Merge branch 'adam-sfp'

Improve sfp handling
Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parents 2afb2025 3f9d30d9
......@@ -57,6 +57,10 @@
* ------------------------------------------------
*/
#define SFP_DB_EMPTY 0xff
static uint8_t sfpcount = SFP_DB_EMPTY;
uint8_t has_eeprom = 0;
static int i2cif, i2c_addr; /* globals, using the names we always used */
......@@ -137,7 +141,7 @@ static int eeprom_write(uint8_t i2cif, uint8_t i2c_addr, uint32_t offset,
int32_t storage_sfpdb_erase(void)
{
uint8_t sfpcount = 0;
sfpcount = 0;
//just a dummy function that writes '0' to sfp count field of the SFP DB
if (eeprom_write(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount,
......@@ -147,28 +151,44 @@ int32_t storage_sfpdb_erase(void)
return sfpcount;
}
int storage_get_sfp(struct s_sfpinfo * sfp,
uint8_t add, uint8_t pos)
static uint8_t sfp_chksum(uint8_t *ptr)
{
int i;
uint8_t chksum = 0;
/* '-1' because we do not include chksum in computation */
for (i = 0; i < sizeof(struct s_sfpinfo) - 1; ++i)
chksum = (uint8_t) ((uint16_t) chksum + *(ptr++)) & 0xff;
return chksum;
}
int storage_get_sfp(struct s_sfpinfo *sfp, uint8_t oper, uint8_t pos)
{
static uint8_t sfpcount = 0;
uint8_t i, chksum = 0;
uint8_t *ptr;
uint8_t i;
struct s_sfpinfo dbsfp;
if (pos >= SFPS_MAX)
return EE_RET_POSERR; //position in database outside the range
if (pos >= SFPS_MAX) {
/* position in database outside the range */
return EE_RET_POSERR;
}
//read how many SFPs are in the database, but only in the first call (pos==0)
if (!pos
/* Read how many SFPs are in the database, but only in the first call
*/
if (sfpcount == SFP_DB_EMPTY
&& eeprom_read(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount,
sizeof(sfpcount)) != sizeof(sfpcount))
return EE_RET_I2CERR;
if (add && sfpcount == SFPS_MAX) //no more space in the database to add new SFPs
return EE_RET_DBFULL;
else if (!pos && !add && sfpcount == 0) //there are no SFPs in the database to read
return sfpcount;
/* for not written flash set sfpcount to 0 */
if (sfpcount == SFP_DB_EMPTY)
sfpcount = 0;
if (oper == SFP_GET) {
if (sfpcount == 0) {
/* There are no SFPs in the database to read */
return 0;
}
if (!add) {
if (eeprom_read(i2cif, i2c_addr,
EE_BASE_SFP + sizeof(sfpcount)
+ pos * sizeof(struct s_sfpinfo),
......@@ -176,27 +196,42 @@ int storage_get_sfp(struct s_sfpinfo * sfp,
!= sizeof(struct s_sfpinfo) )
return EE_RET_I2CERR;
ptr = (uint8_t *) sfp;
for (i = 0; i < sizeof(struct s_sfpinfo) - 1; ++i) //'-1' because we do not include chksum in computation
chksum =
(uint8_t) ((uint16_t) chksum + *(ptr++)) & 0xff;
if (chksum != sfp->chksum)
if (sfp_chksum((uint8_t *)sfp) != sfp->chksum)
return EE_RET_CORRPT;
} else {
/*count checksum */
ptr = (uint8_t *) sfp;
for (i = 0; i < sizeof(struct s_sfpinfo) - 1; ++i) //'-1' because we do not include chksum in computation
chksum =
(uint8_t) ((uint16_t) chksum + *(ptr++)) & 0xff;
sfp->chksum = chksum;
/*add SFP at the end of DB */
}
if (oper == SFP_ADD) {
for (i = 0; i < sfpcount; i++) {
if (eeprom_read(i2cif, i2c_addr,
EE_BASE_SFP + sizeof(sfpcount)
+ i * sizeof(struct s_sfpinfo),
(uint8_t *)&dbsfp, sizeof(struct s_sfpinfo))
!= sizeof(struct s_sfpinfo))
return EE_RET_I2CERR;
if (!strncmp(dbsfp.pn, sfp->pn, 16)) { /* sfp matched */
pp_printf("Update existing SFP entry\n");
break;
}
}
if (i >= SFPS_MAX) { /* database is full */
return EE_RET_DBFULL;
}
/* Count checksum */
sfp->chksum = sfp_chksum((uint8_t *)sfp);
/* Add an entry at the given pos in the DB */
eeprom_write(i2cif, i2c_addr,
EE_BASE_SFP + sizeof(sfpcount)
+ sfpcount * sizeof(struct s_sfpinfo),
+ i * sizeof(struct s_sfpinfo),
(uint8_t *) sfp, sizeof(struct s_sfpinfo));
sfpcount++;
eeprom_write(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount,
sizeof(sfpcount));
if (i >= sfpcount) {
pp_printf("Adding new SFP entry\n");
/* We're adding a new entry, update sfpcount */
sfpcount++;
eeprom_write(i2cif, i2c_addr, EE_BASE_SFP, &sfpcount,
sizeof(sfpcount));
}
}
return sfpcount;
......@@ -204,19 +239,15 @@ int storage_get_sfp(struct s_sfpinfo * sfp,
int storage_match_sfp(struct s_sfpinfo * sfp)
{
uint8_t sfpcount = 1;
int8_t i, temp;
int8_t i;
int sfp_cnt = 1;
struct s_sfpinfo dbsfp;
for (i = 0; i < sfpcount; ++i) {
temp = storage_get_sfp(&dbsfp, 0, i);
if (!i) {
sfpcount = temp; //only in first round valid sfpcount is returned from eeprom_get_sfp
if (sfpcount == 0 || sfpcount == 0xFF)
return 0;
else if (sfpcount < 0)
return sfpcount;
}
for (i = 0; i < sfp_cnt; ++i) {
sfp_cnt = storage_get_sfp(&dbsfp, SFP_GET, i);
if (sfp_cnt <= 0)
return sfp_cnt;
if (!strncmp(dbsfp.pn, sfp->pn, 16)) {
sfp->dTx = dbsfp.dTx;
sfp->dRx = dbsfp.dRx;
......
......@@ -80,6 +80,11 @@ int flash_write(uint32_t addr, uint8_t *buf, int count)
}
bbspi_transfer(1,0);
/* make sure the write is complete */
while (flash_rsr() & 0x01) {
/* do nothing */
}
return count;
}
......
......@@ -402,8 +402,7 @@ static int sfp_valid(struct s_sfpinfo *sfp)
return 1;
}
int storage_get_sfp(struct s_sfpinfo * sfp,
uint8_t add, uint8_t pos)
static int sfp_entry(struct s_sfpinfo *sfp, uint8_t oper, uint8_t pos)
{
static uint8_t sfpcount = 0;
struct s_sfpinfo tempsfp;
......@@ -417,27 +416,35 @@ int storage_get_sfp(struct s_sfpinfo * sfp,
if (sdbfs_open_id(&wrc_sdb, SDB_VENDOR, SDB_DEV_SFP) < 0)
return -1;
//read how many SFPs are in the database, but only in the first call
/* Read how many SFPs are in the database, but only in the first
* call */
if(!pos) {
sfpcount = 0;
while (sdbfs_fread(&wrc_sdb, sizeof(sfpcount) +
sfpcount*sizeof(tempsfp), &tempsfp,
sizeof(tempsfp)) == sizeof(tempsfp)) {
while (sdbfs_fread(&wrc_sdb, sizeof(sfpcount)
+ sfpcount * sizeof(tempsfp),
&tempsfp, sizeof(tempsfp))
== sizeof(tempsfp)) {
if(!sfp_valid(&tempsfp))
break;
sfpcount++;
}
}
if (add && sfpcount == SFPS_MAX) //no more space to add new SFPs
return EE_RET_DBFULL;
if (!pos && !add && sfpcount == 0) // no SFPs in the database
return 0;
if ((oper == SFP_ADD) && (sfpcount == SFPS_MAX)) {
/* no more space to add new SFPs */
ret = EE_RET_DBFULL;
goto out;
}
if (!pos && (oper == SFP_GET) && sfpcount == 0) {
/* no SFPs in the database */
ret = 0;
goto out;
}
if (!add) {
if (oper == SFP_GET) {
if (sdbfs_fread(&wrc_sdb, sizeof(sfpcount) + pos * sizeof(*sfp),
sfp, sizeof(*sfp))
sfp, sizeof(*sfp))
!= sizeof(*sfp))
goto out;
......@@ -449,8 +456,9 @@ int storage_get_sfp(struct s_sfpinfo * sfp,
pp_printf("sfp: corrupted checksum\n");
goto out;
}
} else {
/*count checksum */
}
if (oper == SFP_ADD) {
/* count checksum */
ptr = (uint8_t *)sfp;
/* use sizeof() - 1 because we don't include checksum */
for (i = 0; i < sizeof(struct s_sfpinfo) - 1; ++i)
......@@ -458,37 +466,91 @@ int storage_get_sfp(struct s_sfpinfo * sfp,
sfp->chksum = chksum;
/* add SFP at the end of DB */
if (sdbfs_fwrite(&wrc_sdb, sizeof(sfpcount)
+ sfpcount * sizeof(*sfp), sfp, sizeof(*sfp))
!= sizeof(*sfp))
+ sfpcount * sizeof(*sfp),
sfp, sizeof(*sfp))
!= sizeof(*sfp)) {
goto out;
}
sfpcount++;
if (sdbfs_fwrite(&wrc_sdb, 0, &sfpcount, sizeof(sfpcount))
!= sizeof(sfpcount))
goto out;
}
ret = sfpcount;
out:
sdbfs_close(&wrc_sdb);
return ret;
return 0;
}
static int storage_update_sfp(struct s_sfpinfo *sfp)
{
int sfpcount = 1;
int temp;
int8_t i;
struct s_sfpinfo sfp_db[SFPS_MAX];
struct s_sfpinfo *dbsfp;
/* copy entries from flash to the memory, update entry if matched */
for (i = 0; i < sfpcount; ++i) {
dbsfp = &sfp_db[i];
sfpcount = sfp_entry(dbsfp, SFP_GET, i);
if (sfpcount <= 0)
return sfpcount;
if (!strncmp(dbsfp->pn, sfp->pn, 16)) {
/* update matched entry */
dbsfp->dTx = sfp->dTx;
dbsfp->dRx = sfp->dRx;
dbsfp->alpha = sfp->alpha;
}
}
/* erase entire database */
if (storage_sfpdb_erase() == EE_RET_I2CERR) {
pp_printf("Could not erase DB\n");
return -1;
}
/* add all SFPs */
for (i = 0; i < sfpcount; ++i) {
dbsfp = &sfp_db[i];
temp = sfp_entry(dbsfp, SFP_ADD, 0);
if (temp < 0) {
/* if error, return it */
return temp;
}
}
return i;
}
int storage_get_sfp(struct s_sfpinfo *sfp, uint8_t oper, uint8_t pos)
{
struct s_sfpinfo tmp_sfp;
if (oper == SFP_GET) {
/* Get SFP entry */
return sfp_entry(sfp, SFP_GET, pos);
}
/* storage_match_sfp replaces content of parameter, so do the copy
* first */
tmp_sfp = *sfp;
if (!storage_match_sfp(&tmp_sfp)) { /* add a new sfp entry */
pp_printf("Adding new SFP entry\n");
return sfp_entry(sfp, SFP_ADD, 0);
}
pp_printf("Update existing SFP entry\n");
return storage_update_sfp(sfp);
}
int storage_match_sfp(struct s_sfpinfo * sfp)
{
uint8_t sfpcount = 1;
int8_t i, temp;
int8_t i;
struct s_sfpinfo dbsfp;
for (i = 0; i < sfpcount; ++i) {
temp = storage_get_sfp(&dbsfp, 0, i);
if (!i) {
// first round: valid sfpcount is returned
sfpcount = temp;
if (sfpcount == 0 || sfpcount == 0xFF)
return 0;
else if (sfpcount < 0)
return sfpcount;
}
sfpcount = sfp_entry(&dbsfp, SFP_GET, i);
if (sfpcount <= 0)
return sfpcount;
if (!strncmp(dbsfp.pn, sfp->pn, 16)) {
sfp->dTx = dbsfp.dTx;
sfp->dRx = dbsfp.dRx;
......
......@@ -10,10 +10,21 @@
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include "syscon.h"
#include "i2c.h"
#include "sfp.h"
#include "storage.h"
/* Calibration data (from EEPROM if available) */
int32_t sfp_alpha = 73622176; /* default values if could not read EEPROM */
int32_t sfp_deltaTx = 0;
int32_t sfp_deltaRx = 0;
int32_t sfp_in_db = 0;
char sfp_pn[SFP_PN_LEN];
int sfp_present(void)
{
......@@ -52,3 +63,27 @@ int sfp_read_part_id(char *part_id)
return -1;
}
int sfp_match(void)
{
struct s_sfpinfo sfp;
sfp_pn[0] = '\0';
if (!sfp_present()) {
return -ENODEV;
}
if (sfp_read_part_id(sfp_pn)) {
return -EIO;
}
strncpy(sfp.pn, sfp_pn, SFP_PN_LEN);
if (storage_match_sfp(&sfp) == 0) {
sfp_in_db = SFP_NOT_MATCHED;
return -ENXIO;
}
sfp_deltaTx = sfp.dTx;
sfp_deltaRx = sfp.dRx;
sfp_alpha = sfp.alpha;
sfp_in_db = SFP_MATCHED;
return 0;
}
......@@ -9,10 +9,27 @@
#include <stdint.h>
#define SFP_PN_LEN 16
#define SFP_NOT_MATCHED 1
#define SFP_MATCHED 2
#define SFP_GET 0
#define SFP_ADD 1
extern char sfp_pn[SFP_PN_LEN];
extern int32_t sfp_in_db;
extern int32_t sfp_alpha;
extern int32_t sfp_deltaTx;
extern int32_t sfp_deltaRx;
/* Returns 1 if there's a SFP transceiver inserted in the socket. */
int sfp_present(void);
/* Reads the part ID of the SFP from its configuration EEPROM */
int sfp_read_part_id(char *part_id);
/* Match plugged SFP with a DB entry */
int sfp_match(void);
#endif
......@@ -9,21 +9,43 @@
#ifndef __STORAGE_H
#define __STORAGE_H
#include "sfp.h"
#define SFP_SECTION_PATTERN 0xdeadbeef
#if defined CONFIG_LEGACY_EEPROM
#define EE_BASE_CAL (4 * 1024)
#define EE_BASE_SFP (4 * 1024 + 4)
/* Limit SFPs to 3, see comments below why. */
#define SFPS_MAX 3
/* The definition of EE_BASE_INIT below is wrong! But kept for backward
* compatibility. */
#define EE_BASE_INIT (4 * 1024 + 4 * 29)
/* It should be:
* #define EE_BASE_INIT (EE_BASE_SFP + sizeof(sfpcount) + \
* SFPS_MAX * sizeof(struct s_sfpinfo))
* The used definition define the start of the init script 5 bytes
* (sizeof(sfpcount) + sizeof(t24p)) before the end of SFP database.
* To make the init script working during the update of old versions of wrpc
* SFPS_MAX is limited to 3. Adding the 4th SFP will corrupt the init script
* anyway.
* If someone needs to have 4 SFPs in the database SFPS_MAX can be set to 4 and
* the proper define should be used.
* SDB is not affected by this bug.
*/
#endif
#if defined CONFIG_SDB_STORAGE
#define SFPS_MAX 4
#define SFP_PN_LEN 16
#define EE_BASE_CAL 4*1024
#define EE_BASE_SFP 4*1024+4
#define EE_BASE_INIT 4*1024+SFPS_MAX*29
#endif
#define EE_RET_I2CERR -1
#define EE_RET_DBFULL -2
#define EE_RET_CORRPT -3
#define EE_RET_POSERR -4
extern int32_t sfp_alpha;
extern int32_t sfp_deltaTx;
extern int32_t sfp_deltaRx;
extern uint32_t cal_phase_transition;
extern uint8_t has_eeprom;
......
......@@ -7,18 +7,18 @@
*
* Released according to the GNU GPL, version 2 or any later version.
*/
/* Command: sfp
Arguments: subcommand [subcommand-specific args]
Description: SFP detection/database manipulation.
Subcommands:
add vendor_type delta_tx delta_rx alpha - adds an SFP to the database, with given alpha/delta_rx/delta_rx values
show - shows the SFP database
match - tries to get calibration parameters from DB for a detected SFP
erase - cleans the SFP database
detect - detects the transceiver type
*/
/* Command: sfp
* Arguments: subcommand [subcommand-specific args]
*
* Description: SFP detection/database manipulation.
* Subcommands:
* add <product_number> <delta_tx> <delta_rx> <alpha> - adds an SFP to
* the database, with given alpha/delta_rx/delta_rx values
* show - shows the SFP database
* match - detects the transceiver type and tries to get calibration parameters
* from DB for a detected SFP
* erase - cleans the SFP database
*/
#include <string.h>
#include <stdlib.h>
......@@ -34,87 +34,90 @@
static int cmd_sfp(const char *args[])
{
int8_t sfpcount = 1, i, temp;
int8_t sfpcount = 1, i, temp, ret;
struct s_sfpinfo sfp;
static char pn[SFP_PN_LEN + 1] = "\0";
if (args[0] && !strcasecmp(args[0], "detect")) {
if (!sfp_present())
pp_printf("No SFP.\n");
else
sfp_read_part_id(pn);
pn[16] = 0;
pp_printf("%s\n", pn);
return 0;
if (!args[0]) {
pp_printf("Wrong parameter\n");
return -EINVAL;
}
// else if (!strcasecmp(args[0], "i2cscan"))
// {
// mi2c_scan(WRPC_FMC_I2C);
// return 0;
// }
else if (!strcasecmp(args[0], "erase")) {
if (storage_sfpdb_erase() ==
EE_RET_I2CERR)
if (!strcasecmp(args[0], "erase")) {
if (storage_sfpdb_erase() == EE_RET_I2CERR) {
pp_printf("Could not erase DB\n");
return -EIO;
}
return 0;
} else if (args[4] && !strcasecmp(args[0], "add")) {
if (strlen(args[1]) > 16)
temp = 16;
else
temp = strlen(args[1]);
temp = strnlen(args[1], SFP_PN_LEN);
for (i = 0; i < temp; ++i)
sfp.pn[i] = args[1][i];
while (i < 16)
while (i < SFP_PN_LEN)
sfp.pn[i++] = ' '; //padding
sfp.dTx = atoi(args[2]);
sfp.dRx = atoi(args[3]);
sfp.alpha = atoi(args[4]);
temp = storage_get_sfp(&sfp, 1, 0);
if (temp == EE_RET_DBFULL)
temp = storage_get_sfp(&sfp, SFP_ADD, 0);
if (temp == EE_RET_DBFULL) {
pp_printf("SFP DB is full\n");
else if (temp == EE_RET_I2CERR)
return -ENOSPC;
} else if (temp == EE_RET_I2CERR) {
pp_printf("I2C error\n");
else
pp_printf("%d SFPs in DB\n", temp);
} else if (args[0] && !strcasecmp(args[0], "show")) {
return -EIO;
} else if (temp < 0) {
pp_printf("SFP database error (%d)\n", temp);
return -EFAULT;
}
pp_printf("%d SFPs in DB\n", temp);
return 0;
} else if (!strcasecmp(args[0], "show")) {
for (i = 0; i < sfpcount; ++i) {
temp = storage_get_sfp(&sfp, 0, i);
if (!i) {
sfpcount = temp; //only in first round valid sfpcount is returned from storage_get_sfp
if (sfpcount == 0 || sfpcount == 0xFF) {
pp_printf("SFP database empty...\n");
return 0;
} else if (sfpcount == -1) {
pp_printf("SFP database corrupted...\n");
return 0;
}
sfpcount = storage_get_sfp(&sfp, SFP_GET, i);
if (sfpcount == 0) {
pp_printf("SFP database empty\n");
return 0;
} else if (sfpcount < 0) {
pp_printf("SFP database error (%d)\n",
sfpcount);
return -EFAULT;
}
pp_printf("%d: PN:", i + 1);
for (temp = 0; temp < 16; ++temp)
for (temp = 0; temp < SFP_PN_LEN; ++temp)
pp_printf("%c", sfp.pn[temp]);
pp_printf(" dTx: %d, dRx: %d, alpha: %d\n", sfp.dTx,
pp_printf(" dTx: %8d dRx: %8d alpha: %8d\n", sfp.dTx,
sfp.dRx, sfp.alpha);
}
} else if (args[0] && !strcasecmp(args[0], "match")) {
if (pn[0] == '\0') {
pp_printf("Run sfp detect first\n");
return 0;
return 0;
} else if (!strcasecmp(args[0], "match")) {
ret = sfp_match();
if (ret == -ENODEV) {
pp_printf("No SFP.\n");
return ret;
}
if (ret == -EIO) {
pp_printf("SFP read error\n");
return ret;
}
strncpy(sfp.pn, pn, SFP_PN_LEN);
if (storage_match_sfp(&sfp) > 0) {
pp_printf("SFP matched, dTx=%d, dRx=%d, alpha=%d\n",
sfp.dTx, sfp.dRx, sfp.alpha);
sfp_deltaTx = sfp.dTx;
sfp_deltaRx = sfp.dRx;
sfp_alpha = sfp.alpha;
} else
/* SFP read correctly */
for (temp = 0; temp < SFP_PN_LEN; ++temp)
pp_printf("%c", sfp_pn[temp]);
pp_printf("\n");
if (ret == -ENXIO) {
pp_printf("Could not match to DB\n");
return 0;
} else if (args[0] && !strcasecmp(args[0], "ena")) {
if(!args[1])
return -EINVAL;
return ret;
}
/* match successful */
pp_printf("SFP matched, dTx=%d dRx=%d alpha=%d\n",
sfp.dTx, sfp.dRx, sfp.alpha);
return ret;
} else if (args[1] && !strcasecmp(args[0], "ena")) {
ep_sfp_enable(atoi(args[1]));
return 0;
} else {
pp_printf("Wrong parameter\n");
return -EINVAL;
}
return 0;
}
......
......@@ -38,11 +38,6 @@ int wrc_ui_mode = UI_SHELL_MODE;
int wrc_ui_refperiod = TICS_PER_SECOND; /* 1 sec */
int wrc_phase_tracking = 1;
///////////////////////////////////
//Calibration data (from EEPROM if available)
int32_t sfp_alpha = 73622176; //default values if could not read EEPROM
int32_t sfp_deltaTx = 0;
int32_t sfp_deltaRx = 0;
uint32_t cal_phase_transition = 2389;
int wrc_vlan_number = CONFIG_VLAN_NR;
......@@ -121,6 +116,7 @@ static int wrc_check_link(void)
if (!prev_state && state) {
wrc_verbose("Link up.\n");
gpio_out(GPIO_LED_LINK, 1);
sfp_match();
wrc_ptp_start();
link_status = LINK_WENT_UP;
rv = 1;
......
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