Skip to content

Commit

Permalink
add dynamic transceiver tuning support (sonic-net#821)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sudharsan D.G authored and lguohan committed Jun 4, 2019
1 parent 1ebe89a commit d616764
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 0 deletions.
3 changes: 3 additions & 0 deletions doc/swss-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Stores information for physical switch ports managed by the switch chip. Ports t
mtu = 1*4DIGIT ; port MTU
fec = 1*64VCHAR ; port fec mode
autoneg = BIT ; auto-negotiation mode
preemphasis = 1*8HEXDIG *( "," 1*8HEXDIG) ; list of hex values, one per lane
idriver = 1*8HEXDIG *( "," 1*8HEXDIG) ; list of hex values, one per lane
ipredriver = 1*8HEXDIG *( "," 1*8HEXDIG) ; list of hex values, one per lane

;QOS Mappings
map_dscp_to_tc = ref_hash_key_reference
Expand Down
104 changes: 104 additions & 0 deletions orchagent/portsorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1519,6 +1519,9 @@ void PortsOrch::doPortTask(Consumer &consumer)
if (op == SET_COMMAND)
{
set<int> lane_set;
vector<uint32_t> pre_emphasis;
vector<uint32_t> idriver;
vector<uint32_t> ipredriver;
string admin_status;
string fec_mode;
string pfc_asym;
Expand Down Expand Up @@ -1575,6 +1578,24 @@ void PortsOrch::doPortTask(Consumer &consumer)
{
an = (int)stoul(fvValue(i));
}

/* Set port serdes Pre-emphasis */
if (fvField(i) == "preemphasis")
{
getPortSerdesVal(fvValue(i), pre_emphasis);
}

/* Set port serdes idriver */
if (fvField(i) == "idriver")
{
getPortSerdesVal(fvValue(i), idriver);
}

/* Set port serdes ipredriver */
if (fvField(i) == "ipredriver")
{
getPortSerdesVal(fvValue(i), ipredriver);
}
}

/* Collect information about all received ports */
Expand Down Expand Up @@ -1855,6 +1876,51 @@ void PortsOrch::doPortTask(Consumer &consumer)
}
}

if (pre_emphasis.size() != 0)
{
if (setPortSerdesAttribute(p.m_port_id, SAI_PORT_ATTR_SERDES_PREEMPHASIS, pre_emphasis))
{
SWSS_LOG_NOTICE("Set port %s preemphasis is success", alias.c_str());
}
else
{
SWSS_LOG_ERROR("Failed to set port %s pre-emphasis", alias.c_str());
it++;
continue;
}

}

if (idriver.size() != 0)
{
if (setPortSerdesAttribute(p.m_port_id, SAI_PORT_ATTR_SERDES_IDRIVER, idriver))
{
SWSS_LOG_NOTICE("Set port %s idriver is success", alias.c_str());
}
else
{
SWSS_LOG_ERROR("Failed to set port %s idriver", alias.c_str());
it++;
continue;
}

}

if (ipredriver.size() != 0)
{
if (setPortSerdesAttribute(p.m_port_id, SAI_PORT_ATTR_SERDES_IPREDRIVER, ipredriver))
{
SWSS_LOG_NOTICE("Set port %s ipredriver is success", alias.c_str());
}
else
{
SWSS_LOG_ERROR("Failed to set port %s ipredriver", alias.c_str());
it++;
continue;
}

}

/* Last step set port admin status */
if (!admin_status.empty() && (p.m_admin_state_up != (admin_status == "up")))
{
Expand Down Expand Up @@ -3297,3 +3363,41 @@ bool PortsOrch::removeAclTableGroup(const Port &p)
return true;
}

bool PortsOrch::setPortSerdesAttribute(sai_object_id_t port_id, sai_attr_id_t attr_id,
vector<uint32_t> &serdes_val)
{
SWSS_LOG_ENTER();

sai_attribute_t attr;

memset(&attr, 0, sizeof(attr));
attr.id = attr_id;

attr.value.u32list.count = (uint32_t)serdes_val.size();
attr.value.u32list.list = serdes_val.data();

sai_status_t status = sai_port_api->set_port_attribute(port_id, &attr);
if (status != SAI_STATUS_SUCCESS)
{
SWSS_LOG_ERROR("Failed to set serdes attribute %d to port pid:%lx",
attr_id, port_id);
return false;
}
return true;
}

void PortsOrch::getPortSerdesVal(const std::string& val_str,
std::vector<uint32_t> &lane_values)
{
SWSS_LOG_ENTER();

uint32_t lane_val;
std::string lane_str;
std::istringstream iss(val_str);

while (std::getline(iss, lane_str, ','))
{
lane_val = (uint32_t)std::stoul(lane_str, NULL, 16);
lane_values.push_back(lane_val);
}
}
5 changes: 5 additions & 0 deletions orchagent/portsorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ class PortsOrch : public Orch, public Subject

bool getPortOperStatus(const Port& port, sai_port_oper_status_t& status) const;
void updatePortOperStatus(Port &port, sai_port_oper_status_t status);

void getPortSerdesVal(const std::string& s, std::vector<uint32_t> &lane_values);

bool setPortSerdesAttribute(sai_object_id_t port_id, sai_attr_id_t attr_id,
vector<uint32_t> &serdes_val);
};
#endif /* SWSS_PORTSORCH_H */

90 changes: 90 additions & 0 deletions tests/test_port.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,93 @@ def test_PortFec(dvs, testlog):
for fv in fvs:
if fv[0] == "SAI_PORT_ATTR_FEC_MODE":
assert fv[1] == "SAI_PORT_FEC_MODE_RS"

def test_PortPreemp(dvs, testlog):

pre_name = 'preemphasis'
pre_val = [0x1234,0x2345,0x3456,0x4567]
pre_val_str = str(hex(pre_val[0])) + "," + str(hex(pre_val[1]))+ "," + \
str(hex(pre_val[2]))+ "," + str(hex(pre_val[3]))

pre_val_asic = '4:' + str(pre_val[0]) + "," + str(pre_val[1]) + "," + \
str(pre_val[2]) + "," + str(pre_val[3])
fvs = swsscommon.FieldValuePairs([(pre_name, pre_val_str)])
db = swsscommon.DBConnector(0, dvs.redis_sock, 0)
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)

tbl = swsscommon.Table(db, "PORT_TABLE")
ptbl = swsscommon.ProducerStateTable(db, "PORT_TABLE")
atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT")

ptbl.set("Ethernet0", fvs)


time.sleep(1)

# get fec
(status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"])
assert status == True

for fv in fvs:
if fv[0] == "SAI_PORT_ATTR_SERDES_PREEMPHASIS":
assert fv[1] == pre_val_asic

def test_PortIdriver(dvs, testlog):

idrv_name = 'idriver'
idrv_val = [0x1,0x1,0x2,0x2]
idrv_val_str = str(hex(idrv_val[0])) + "," + str(hex(idrv_val[1]))+ "," + \
str(hex(idrv_val[2]))+ "," + str(hex(idrv_val[3]))

idrv_val_asic = '4:' + str(idrv_val[0]) + "," + str(idrv_val[1]) + "," + \
str(idrv_val[2]) + "," + str(idrv_val[3])
fvs = swsscommon.FieldValuePairs([(idrv_name, idrv_val_str)])
db = swsscommon.DBConnector(0, dvs.redis_sock, 0)
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)

tbl = swsscommon.Table(db, "PORT_TABLE")
ptbl = swsscommon.ProducerStateTable(db, "PORT_TABLE")
atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT")

ptbl.set("Ethernet0", fvs)


time.sleep(1)

# get fec
(status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"])
assert status == True

for fv in fvs:
if fv[0] == "SAI_PORT_ATTR_SERDES_IDRIVER":
assert fv[1] == idrv_val_asic

def test_PortIpredriver(dvs, testlog):

ipre_name = 'ipredriver'
ipre_val = [0x2,0x3,0x4,0x5]
ipre_val_str = str(hex(ipre_val[0])) + "," + str(hex(ipre_val[1]))+ "," + \
str(hex(ipre_val[2]))+ "," + str(hex(ipre_val[3]))

ipre_val_asic = '4:' + str(ipre_val[0]) + "," + str(ipre_val[1]) + "," + \
str(ipre_val[2]) + "," + str(ipre_val[3])
fvs = swsscommon.FieldValuePairs([(ipre_name, ipre_val_str)])
db = swsscommon.DBConnector(0, dvs.redis_sock, 0)
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)

tbl = swsscommon.Table(db, "PORT_TABLE")
ptbl = swsscommon.ProducerStateTable(db, "PORT_TABLE")
atbl = swsscommon.Table(adb, "ASIC_STATE:SAI_OBJECT_TYPE_PORT")

ptbl.set("Ethernet0", fvs)


time.sleep(1)

# get fec
(status, fvs) = atbl.get(dvs.asicdb.portnamemap["Ethernet0"])
assert status == True

for fv in fvs:
if fv[0] == "SAI_PORT_ATTR_SERDES_IPREDRIVER":
assert fv[1] == ipre_val_asic

0 comments on commit d616764

Please sign in to comment.