+int t4_set_link_fec(struct port_info *pi, u8 fec_rs, u8 fec_baser,
+ u8 fec_none, u32 *new_caps)
+{
+ struct link_config *lc = &pi->link_cfg;
+ u32 max_speed, caps = *new_caps;
+
+ if (!(lc->pcaps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC)))
+ return -EOPNOTSUPP;
+
+ /* Link might be down. In that case consider the max
+ * speed advertised
+ */
+ max_speed = t4_fwcap_to_speed(lc->link_caps);
+ if (!max_speed)
+ max_speed = t4_fwcap_to_speed(lc->acaps);
+
+ caps &= ~V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC);
+ if (fec_rs) {
+ switch (max_speed) {
+ case 100000:
+ case 25000:
+ caps |= FW_PORT_CAP32_FEC_RS;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (fec_baser) {
+ switch (max_speed) {
+ case 50000:
+ case 25000:
+ caps |= FW_PORT_CAP32_FEC_BASER_RS;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ if (fec_none)
+ caps |= FW_PORT_CAP32_FEC_NO_FEC;
+
+ if (!(caps & V_FW_PORT_CAP32_FEC(M_FW_PORT_CAP32_FEC))) {
+ /* No explicit encoding is requested.
+ * So, default back to AUTO.
+ */
+ switch (max_speed) {
+ case 100000:
+ caps |= FW_PORT_CAP32_FEC_RS |
+ FW_PORT_CAP32_FEC_NO_FEC;
+ break;
+ case 50000:
+ caps |= FW_PORT_CAP32_FEC_BASER_RS |
+ FW_PORT_CAP32_FEC_NO_FEC;
+ break;
+ case 25000:
+ caps |= FW_PORT_CAP32_FEC_RS |
+ FW_PORT_CAP32_FEC_BASER_RS |
+ FW_PORT_CAP32_FEC_NO_FEC;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ *new_caps = caps;
+
+ return 0;
+}
+