Example #1
0
double QsfpModule::getQsfpSensor(SffField field,
    double (*conversion)(uint16_t value)) {

  auto info = SffFieldInfo::getSffFieldAddress(qsfpFields, field);
  const uint8_t *data = getQsfpValuePtr(info.dataAddress,
                                        info.offset, info.length);
  return conversion(data[0] << 8 | data[1]);
}
Example #2
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 #3
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 #4
0
int QsfpModule::getQsfpCableLength(SffField field) {
    int length;
    auto info = SffFieldInfo::getSffFieldAddress(qsfpFields, field);
    const uint8_t *data = getQsfpValuePtr(info.dataAddress,
                                          info.offset, info.length);
    auto multiplier = qsfpMultiplier.at(field);
    length = *data * multiplier;
    if (*data == MAX_CABLE_LEN) {
        length = -(MAX_CABLE_LEN - 1) * multiplier;
    }
    return length;
}
Example #5
0
/*
 * Cable length is report as a single byte;  each field has a
 * specific multiplier to use to get the true length.  For instance,
 * single mode fiber length is specified in km, so the multiplier
 * is 1000.  In addition, the raw value of 255 indicates that the
 * cable is longer than can be represented.  We use a negative
 * value of the appropriate magnitude to communicate that to thrift
 * clients.
 */
double QsfpModule::getQsfpCableLength(SffField field) const {
  double length;
  auto info = SffFieldInfo::getSffFieldAddress(qsfpFields, field);
  const uint8_t *data = getQsfpValuePtr(info.dataAddress,
                                        info.offset, info.length);
  auto multiplier = qsfpMultiplier.at(field);
  length = *data * multiplier;
  if (*data == EEPROM_DEFAULT) {
    // TODO: does this really mean the cable is too long?
    length = -(EEPROM_DEFAULT - 1) * multiplier;
  }
  return length;
}
Example #6
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 #7
0
int QsfpModule::getQsfpDACGauge() const {
  auto info = SffFieldInfo::getSffFieldAddress(qsfpFields, SffField::DAC_GAUGE);
  const uint8_t *val = getQsfpValuePtr(info.dataAddress,
                                       info.offset, info.length);
  //Guard against FF default value
  auto gauge = *val;
  if (gauge == EEPROM_DEFAULT) {
    return 0;
  } else if (gauge > MAX_GAUGE) {
    // HACK: We never use cables with more than 30 (in decimal) gauge
    // However, some vendors put in hex values. For example, some put
    // 0x28 to represent 28 gauge cable (why?!?), which we would
    // incorrectly interpret as 40 if using decimal. This converts
    // values > 30 to the hex value.
    return (gauge / HEX_BASE) * DECIMAL_BASE + gauge % HEX_BASE;
  } else{
    return gauge;
  }
}
Example #8
0
TransmitterTechnology QsfpModule::getQsfpTransmitterTechnology() {
  auto info = SffFieldInfo::getSffFieldAddress(qsfpFields,
      SffField::DEVICE_TECHNOLOGY);
  try {
    const uint8_t* data =
        getQsfpValuePtr(info.dataAddress, info.offset, info.length);
    uint8_t transTech = *data >> DeviceTechnology::TRANSMITTER_TECH_SHIFT;
    if (transTech == DeviceTechnology::UNKNOWN_VALUE) {
      return TransmitterTechnology::UNKNOWN;
    } else if (transTech <= DeviceTechnology::OPTICAL_MAX_VALUE) {
      return TransmitterTechnology::OPTICAL;
    } else {
      return TransmitterTechnology::COPPER;
    }
  } catch (const std::exception& e) {
    LOG(INFO) << " Unable to get transmitter technology for QSFP: "
              << qsfpImpl_->getName();
  }
  return TransmitterTechnology::UNKNOWN;
}
Example #9
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 #10
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 #11
0
void QsfpModule::getQsfpValue(int dataAddress, int offset, int length,
                              uint8_t* data) const {
  const uint8_t *ptr = getQsfpValuePtr(dataAddress, offset, length);

  memcpy(data, ptr, length);
}
Example #12
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 #13
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";
    }
}