Example #1
0
uint8_t QsfpModule::getSettingsValue(SffField field, uint8_t mask) {
  int offset;
  int length;
  int dataAddress;

  getQsfpFieldAddress(field, dataAddress, offset, length);
  const uint8_t* data = getQsfpValuePtr(dataAddress, offset, length);

  return data[0] & mask;
}
Example #2
0
FlagLevels QsfpModule::getQsfpSensorFlags(SffField fieldName) {
  int offset;
  int length;
  int dataAddress;

  /* Determine if QSFP is present */
  getQsfpFieldAddress(fieldName, dataAddress, offset, length);
  const uint8_t *data = getQsfpValuePtr(dataAddress, offset, length);
  return getQsfpFlags(data, 4);
}
Example #3
0
void QsfpModule::setCdrIfSupported(cfg::PortSpeed speed,
                                   FeatureState currentStateTx,
                                   FeatureState currentStateRx) {
  /*
   * Note that this function expects to be called with qsfpModuleMutex_
   * held.
   */

  LOG(INFO) << "Checking if we need to change CDR on "
            << folly::to<std::string>(qsfpImpl_->getName());

  if (currentStateTx == FeatureState::UNSUPPORTED &&
      currentStateRx == FeatureState::UNSUPPORTED) {
    LOG(INFO) << "CDR is not supported on "
              << folly::to<std::string>(qsfpImpl_->getName());
    return;
  }

  // If only one of Rx or Tx is supported, it doesn't matter what
  // we set the value to, so in that case, treat is as if
  // no change is needed
  auto toChange = [speed](FeatureState state) {
    return
      state != FeatureState::UNSUPPORTED &&
      ((speed == cfg::PortSpeed::HUNDREDG && state != FeatureState::ENABLED) ||
      (speed != cfg::PortSpeed::HUNDREDG && state != FeatureState::DISABLED));
  };

  bool changeRx = toChange(currentStateRx);
  bool changeTx = toChange(currentStateTx);
  if (!changeRx && !changeTx) {
    LOG(INFO) << "Port: " << folly::to<std::string>(qsfpImpl_->getName()) <<
      " Not changing CDR setting, already correctly set";
    return;
  }

  // If one of rx and tx need a change, set the whole byte - whichever
  // isn't supported will be ignored anyway
  FeatureState newState = FeatureState::DISABLED;
  uint8_t value = 0x0;
  if (speed == cfg::PortSpeed::HUNDREDG) {
    value = 0xFF;
    newState = FeatureState::ENABLED;
  }
  int dataLength, dataAddress, dataOffset;
  getQsfpFieldAddress(SffField::CDR_CONTROL, dataAddress,
                      dataOffset, dataLength);

  qsfpImpl_->writeTransceiver(TransceiverI2CApi::ADDR_QSFP, dataOffset,
      sizeof(value), &value);
  LOG(INFO) << folly::to<std::string>("Port: ", qsfpImpl_->getName(),
     " Setting CDR to state: ",
     _FeatureState_VALUES_TO_NAMES.find(newState)->second);
}
Example #4
0
std::string QsfpModule::getQsfpString(SffField field) const {
  int offset;
  int length;
  int dataAddress;

  getQsfpFieldAddress(field, dataAddress, offset, length);
  const uint8_t *data = getQsfpValuePtr(dataAddress, offset, length);

  while (length > 0 && data[length - 1] == ' ') {
    --length;
  }
  return std::string(reinterpret_cast<const char*>(data), length);
}
Example #5
0
void QsfpModule::ensureTxEnabled() {
  // Sometimes transceivers lock up and disable TX. When we customize
  // the transceiver let's also ensure that tx is enabled. We have
  // even seen transceivers report to have tx enabled in the DOM, but
  // no traffic was flowing. When we forcibly set the tx_enable bits
  // again, traffic began flowing.  Because of this, we ALWAYS set the
  // bits (even if they report enabled).
  int offset;
  int length;
  int dataAddress;
  getQsfpFieldAddress(SffField::TX_DISABLE, dataAddress, offset, length);

  std::array<uint8_t, 1> buf = {{0}};
  qsfpImpl_->writeTransceiver(
    TransceiverI2CApi::ADDR_QSFP, offset, 1, buf.data());
}
Example #6
0
int QsfpModule::getFieldValue(SffField fieldName,
                              uint8_t* fieldValue) {
  lock_guard<std::mutex> g(qsfpModuleMutex_);
  int offset;
  int length;
  int dataAddress;

  /* Determine if QSFP is present */
  if (cacheIsValid()) {
    try {
      getQsfpFieldAddress(fieldName, dataAddress, offset, length);
      getQsfpValue(dataAddress, offset, length, fieldValue);
    } catch (const std::exception& ex) {
      LOG(ERROR) << "Error reading field value for transceiver:" <<
             folly::to<std::string>(qsfpImpl_->getName()) << " " << ex.what();
    }
  }
  return -1;
}
Example #7
0
ThresholdLevels QsfpModule::getThresholdValues(SffField field,
                               double (*conversion)(uint16_t value)) {
  int offset;
  int length;
  int dataAddress;
  ThresholdLevels thresh;

  CHECK(!flatMem_);

  getQsfpFieldAddress(field, dataAddress, offset, length);
  const uint8_t *data = getQsfpValuePtr(dataAddress, offset, length);

  CHECK_GE(length, 8);
  thresh.alarm.high = conversion(data[0] << 8 | data[1]);
  thresh.alarm.low = conversion(data[2] << 8 | data[3]);
  thresh.warn.high = conversion(data[4] << 8 | data[5]);
  thresh.warn.low = conversion(data[6] << 8 | data[7]);

  return thresh;
}
Example #8
0
void QsfpModule::setQsfpIdprom() {
uint8_t status[2];
  int offset;
  int length;
  int dataAddress;

  if (!present_) {
    throw FbossError("QSFP IDProm set failed as QSFP is not present");
  }

  // Check if the data is ready
  getQsfpFieldAddress(SffField::STATUS,
                      dataAddress, offset, length);
  getQsfpValue(dataAddress, offset, length, status);
  if (status[1] & (1 << 0)) {
    dirty_ = true;
    throw FbossError("QSFP IDProm failed as QSFP is not ready");
  }
  flatMem_ = status[1] & (1 << 2);
  dirty_ = false;
}
Example #9
0
void QsfpModule::setPowerOverrideIfSupported(PowerControlState currentState) {
  /* Wedge forces Low Power mode via a pin;  we have to reset this
   * to force High Power mode on all transceivers except SR4-40G.
   *
   * Note that this function expects to be called with qsfpModuleMutex_
   * held.
   */

  int offset;
  int length;
  int dataAddress;
  getQsfpFieldAddress(SffField::ETHERNET_COMPLIANCE, dataAddress,
                      offset, length);
  const uint8_t *ether = getQsfpValuePtr(dataAddress, offset, length);

  getQsfpFieldAddress(SffField::EXTENDED_IDENTIFIER, dataAddress,
                      offset, length);
  const uint8_t *extId = getQsfpValuePtr(dataAddress, offset, length);

  auto desiredSetting = PowerControlState::POWER_OVERRIDE;

  // SR4-40G is represented by a value of 2 - SFF-8636
  // This is the only transceiver that should use LP mode
  if (*ether == EthernetCompliance::SR4_40GBASE) {
    desiredSetting = PowerControlState::POWER_LPMODE;
  } else {
    uint8_t highPowerLevel = (*extId & EXT_ID_HI_POWER_MASK);

    if (highPowerLevel > 0) {
      desiredSetting = PowerControlState::HIGH_POWER_OVERRIDE;
    }
  }

  auto portStr = folly::to<std::string>(qsfpImpl_->getName());
  VLOG(1) << "Port " << portStr << ": Power control "
            << _PowerControlState_VALUES_TO_NAMES.find(currentState)->second
            << " Ext ID " << std::hex << (int) *extId
            << " Ethernet compliance " << std::hex << (int) *ether
            << " Desired power control "
            << _PowerControlState_VALUES_TO_NAMES.find(desiredSetting)->second;

  if (currentState == desiredSetting) {
    LOG(INFO) << "Port: " << folly::to<std::string>(qsfpImpl_->getName()) <<
      " Power override already correctly set, doing nothing";
    return;
  }

  uint8_t power = uint8_t(PowerControl::POWER_OVERRIDE);
  if (desiredSetting == PowerControlState::HIGH_POWER_OVERRIDE) {
    power = uint8_t(PowerControl::HIGH_POWER_OVERRIDE);
  } else if (desiredSetting == PowerControlState::POWER_LPMODE) {
    power = uint8_t(PowerControl::POWER_LPMODE);
  }

  getQsfpFieldAddress(SffField::POWER_CONTROL, dataAddress,
                      offset, length);
  qsfpImpl_->writeTransceiver(TransceiverI2CApi::ADDR_QSFP,
      offset, sizeof(power), &power);
  LOG(INFO) << "Port " << portStr
            << ": QSFP set to power setting "
            << _PowerControlState_VALUES_TO_NAMES.find(desiredSetting)->second
            << " (" << int(power) << ")";
}
Example #10
0
void QsfpModule::setRateSelectIfSupported(cfg::PortSpeed speed,
    RateSelectState currentState, RateSelectSetting currentSetting) {
  if (currentState == RateSelectState::UNSUPPORTED) {
    return;
  } else if (currentState == RateSelectState::APPLICATION_RATE_SELECT) {
    // Currently only support extended rate select, so treat application
    // rate select as an invalid option
    throw FbossError(folly::to<std::string>("Port: ", qsfpImpl_->getName(),
      " Rate select in unknown state, treating as unsupported: ",
      _RateSelectState_VALUES_TO_NAMES.find(currentState)->second));
  }

  uint8_t value;
  RateSelectSetting newSetting;
  bool alreadySet = false;
  auto translateEnum = [currentSetting, &value, &newSetting] (
      RateSelectSetting desired,
      uint8_t newValue) {
    if (currentSetting == desired) {
      return true;
    }
    newSetting = desired;
    value = newValue;
    return false;
  };

  if (currentState == RateSelectState::EXTENDED_RATE_SELECT_V1) {
    // Use the highest possible speed in this version
    alreadySet = translateEnum(RateSelectSetting::FROM_6_6GB_AND_ABOVE,
        0b10101010);
  } else if (speed == cfg::PortSpeed::FORTYG) {
    // Optimised for 10G channels
    alreadySet = translateEnum(RateSelectSetting::LESS_THAN_12GB,
      0b00000000);
  } else if (speed == cfg::PortSpeed::HUNDREDG) {
    // Optimised for 25GB channels
    alreadySet = translateEnum(RateSelectSetting::FROM_24GB_to_26GB,
        0b10101010);
  } else {
    throw FbossError(folly::to<std::string>("Port: ", qsfpImpl_->getName(),
      " Unable to set rate select for port speed: ",
      cfg::_PortSpeed_VALUES_TO_NAMES.find(speed)->second));
  }

  if (alreadySet) {
    return;
  }

  int dataLength, dataAddress, dataOffset;

  getQsfpFieldAddress(SffField::RATE_SELECT_RX, dataAddress,
                      dataOffset, dataLength);
  qsfpImpl_->writeTransceiver(TransceiverI2CApi::ADDR_QSFP,
      dataOffset, sizeof(value), &value);

  getQsfpFieldAddress(SffField::RATE_SELECT_RX, dataAddress,
                      dataOffset, dataLength);
  qsfpImpl_->writeTransceiver(TransceiverI2CApi::ADDR_QSFP,
      dataOffset, sizeof(value), &value);
  LOG(INFO) << "Port: " << folly::to<std::string>(qsfpImpl_->getName()) <<
    " set rate select to " <<
    _RateSelectSetting_VALUES_TO_NAMES.find(newSetting)->second;
}
Example #11
0
bool QsfpModule::getSensorsPerChanInfo(std::vector<Channel>& channels) {
  int offset;
  int length;
  int dataAddress;

  /*
   * Interestingly enough, the QSFP stores the four alarm flags
   * (alarm high, alarm low, warning high, warning low) in two bytes by
   * channel in order 2, 1, 4, 3;  by using this set of offsets, we
   * should be able to read them in order, by reading the appriopriate
   * bit offsets combined with a byte offset into the data.
   *
   * That is, read bits 4 through 7 of the first byte, then 0 through 3,
   * then 4 through 7 of the second byte, and so on.  Ugh.
   */
  int bitOffset[] = {4, 0, 4, 0};
  int byteOffset[] = {0, 0, 1, 1};

  getQsfpFieldAddress(SffField::CHANNEL_RX_PWR_ALARMS, dataAddress,
                      offset, length);
  const uint8_t *data = getQsfpValuePtr(dataAddress, offset, length);

  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    channels[channel].sensors.rxPwr.flags =
      getQsfpFlags(data + byteOffset[channel], bitOffset[channel]);
    channels[channel].sensors.rxPwr.__isset.flags = true;
  }

  getQsfpFieldAddress(SffField::CHANNEL_TX_BIAS_ALARMS, dataAddress,
                      offset, length);
  data = getQsfpValuePtr(dataAddress, offset, length);

  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    channels[channel].sensors.txBias.flags =
      getQsfpFlags(data + byteOffset[channel], bitOffset[channel]);
    channels[channel].sensors.txBias.__isset.flags = true;
  }

  getQsfpFieldAddress(SffField::CHANNEL_TX_PWR_ALARMS, dataAddress,
                      offset, length);
  data = getQsfpValuePtr(dataAddress, offset, length);

  for (int channel = 0; channel < CHANNEL_COUNT; channel++) {
    channels[channel].sensors.txPwr.flags =
      getQsfpFlags(data + byteOffset[channel], bitOffset[channel]);
    channels[channel].sensors.txPwr.__isset.flags = true;
  }


  getQsfpFieldAddress(SffField::CHANNEL_RX_PWR, dataAddress,
                      offset, length);
  data = getQsfpValuePtr(dataAddress, offset, length);

  for (auto& channel : channels) {
    uint16_t value = data[0] << 8 | data[1];
    channel.sensors.rxPwr.value = SffFieldInfo::getPwr(value);
    data += 2;
    length--;
  }
  CHECK_GE(length, 0);

  getQsfpFieldAddress(SffField::CHANNEL_TX_BIAS, dataAddress,
                      offset, length);
  data = getQsfpValuePtr(dataAddress, offset, length);
  for (auto& channel : channels) {
    uint16_t value = data[0] << 8 | data[1];
    channel.sensors.txBias.value = SffFieldInfo::getTxBias(value);
    data += 2;
    length--;
  }
  CHECK_GE(length, 0);

  getQsfpFieldAddress(SffField::CHANNEL_TX_PWR, dataAddress,
                      offset, length);
  data = getQsfpValuePtr(dataAddress, offset, length);

  for (auto& channel : channels) {
    uint16_t value = data[0] << 8 | data[1];
    channel.sensors.txPwr.value = SffFieldInfo::getPwr(value);
    data += 2;
    length--;
  }
  CHECK_GE(length, 0);

  return true;
}
Example #12
0
void QsfpModule::customizeTransceiver() {
    /*
     * Determine whether we need to customize any of the QSFP registers.
     * Wedge forces Low Power mode via a pin;  we have to reset this
     * to force High Power mode on LR4s.
     *
     * Note that this function expects to be called with qsfpModuleMutex_
     * held.
     */

    if (dirty_ == true) {
        return;
    }

    int offset;
    int length;
    int dataAddress;

    getQsfpFieldAddress(SffField::EXTENDED_IDENTIFIER, dataAddress,
                        offset, length);
    const uint8_t *extId = getQsfpValuePtr(dataAddress, offset, length);
    getQsfpFieldAddress(SffField::ETHERNET_COMPLIANCE, dataAddress,
                        offset, length);
    const uint8_t *ethCompliance = getQsfpValuePtr(dataAddress, offset, length);

    int pwrCtrlAddress;
    int pwrCtrlOffset;
    int pwrCtrlLength;
    getQsfpFieldAddress(SffField::POWER_CONTROL, pwrCtrlAddress,
                        pwrCtrlOffset, pwrCtrlLength);
    const uint8_t *pwrCtrl = getQsfpValuePtr(pwrCtrlAddress,
                             pwrCtrlOffset, pwrCtrlLength);

    /*
     * It is not clear whether we'll have to use some of these values
     * in future to determine whether or not to set the high power override.
     * Leave the logging in until this is fully debugged -- this should
     * only trigger on QSFP insertion.
     */

    VLOG(1) << "Port: " << folly::to<std::string>(qsfpImpl_->getName()) <<
            " QSFP Ext ID " << std::hex << (int) *extId <<
            " Ether Compliance " << std::hex << (int) *ethCompliance <<
            " Power Control " << std::hex << (int) *pwrCtrl;

    int highPowerLevel = (*extId & EXT_ID_HI_POWER_MASK);
    int powerLevel = (*extId & EXT_ID_MASK) >> EXT_ID_SHIFT;

    if (highPowerLevel > 0 || powerLevel > 0) {
        uint8_t power = POWER_OVERRIDE;
        if (highPowerLevel > 0) {
            power |= HIGH_POWER_OVERRIDE;
        }

        // Note that we don't have to set the page here, but there should
        // probably be a setQsfpValue() function to handle pages, etc.

        if (pwrCtrlAddress != QsfpPages::LOWER) {
            throw FbossError("QSFP failed to set POWER_CONTROL for LR4 "
                             "due to incorrect page number");
        }
        if (pwrCtrlLength != sizeof(power)) {
            throw FbossError("QSFP failed to set POWER_CONTROL for LR4 "
                             "due to incorrect length");
        }

        qsfpImpl_->writeTransceiver(0x50, pwrCtrlOffset, sizeof(power), &power);
        LOG(INFO) << "Port: " << folly::to<std::string>(qsfpImpl_->getName()) <<
                  " QSFP set to override low power";
    }
}