/* Get the SW semaphore */ while (i < timeout) {
swsm = rd32(IGC_SWSM); if (!(swsm & IGC_SWSM_SMBI)) break;
usleep_range(500, 600);
i++;
}
if (i == timeout) { /* In rare circumstances, the SW semaphore may already be held *unintentionally.Clearthesemaphoreoncebeforegivingup.
*/ if (hw->dev_spec._base.clear_semaphore_once) {
hw->dev_spec._base.clear_semaphore_once = false;
igc_put_hw_semaphore(hw); for (i = 0; i < timeout; i++) {
swsm = rd32(IGC_SWSM); if (!(swsm & IGC_SWSM_SMBI)) break;
usleep_range(500, 600);
}
}
/* If we do not have the semaphore here, we have to give up. */ if (i == timeout) {
hw_dbg("Driver can't access device - SMBI bit is set.\n"); return -IGC_ERR_NVM;
}
}
/* Get the FW semaphore. */ for (i = 0; i < timeout; i++) {
swsm = rd32(IGC_SWSM);
wr32(IGC_SWSM, swsm | IGC_SWSM_SWESMBI);
/* Semaphore acquired if bit latched */ if (rd32(IGC_SWSM) & IGC_SWSM_SWESMBI) break;
usleep_range(500, 600);
}
if (i == timeout) { /* Release semaphores */
igc_put_hw_semaphore(hw);
hw_dbg("Driver can't access the NVM\n"); return -IGC_ERR_NVM;
}
/* Releasing the resource requires first getting the HW semaphore. *Ifwefailtogetthesemaphore,thereisnothingwecando, *exceptloganerrorandquit.Wearenotallowedtohanghere *indefinitely,asitmaycausedenialofserviceorsystemcrash.
*/ if (igc_get_hw_semaphore_i225(hw)) {
hw_dbg("Failed to release SW_FW_SYNC.\n"); return;
}
/* We cannot hold synchronization semaphores for too long, *becauseofforcefultakeoverprocedure.Howeveritismoreefficient *toreadinburststhansynchronizingaccessforeachword.
*/ for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
IGC_EERD_EEWR_MAX_COUNT : (words - i);
status = hw->nvm.ops.acquire(hw); if (status) break;
status = igc_read_nvm_eerd(hw, offset, count, data + i);
hw->nvm.ops.release(hw); if (status) break;
}
/* A check for invalid values: offset too large, too many words, *toomanywordsfortheoffset,andnotenoughwords.
*/ if (offset >= nvm->word_size || (words > (nvm->word_size - offset)) ||
words == 0) {
hw_dbg("nvm parameter(s) out of bounds\n"); return ret_val;
}
for (i = 0; i < words; i++) {
ret_val = -IGC_ERR_NVM;
eewr = ((offset + i) << IGC_NVM_RW_ADDR_SHIFT) |
(data[i] << IGC_NVM_RW_REG_DATA) |
IGC_NVM_RW_REG_START;
wr32(IGC_SRWR, eewr);
for (k = 0; k < attempts; k++) { if (IGC_NVM_RW_REG_DONE &
rd32(IGC_SRWR)) {
ret_val = 0; break;
}
udelay(5);
}
/* We cannot hold synchronization semaphores for too long, *becauseofforcefultakeoverprocedure.Howeveritismoreefficient *towriteinburststhansynchronizingaccessforeachword.
*/ for (i = 0; i < words; i += IGC_EERD_EEWR_MAX_COUNT) {
count = (words - i) / IGC_EERD_EEWR_MAX_COUNT > 0 ?
IGC_EERD_EEWR_MAX_COUNT : (words - i);
status = hw->nvm.ops.acquire(hw); if (status) break;
status = igc_write_nvm_srwr(hw, offset, count, data + i);
hw->nvm.ops.release(hw); if (status) break;
}
status = hw->nvm.ops.acquire(hw); if (status) goto out;
/* Replace the read function with semaphore grabbing with *theonethatskipsthisforawhile. *Wehavesemaphoretakenalreadyhere.
*/
read_op_ptr = hw->nvm.ops.read;
hw->nvm.ops.read = igc_read_nvm_eerd;
status = igc_validate_nvm_checksum(hw);
/* Revert original read operation. */
hw->nvm.ops.read = read_op_ptr;
/* Read the first word from the EEPROM. If this times out or fails, do *notcontinueorwecouldbeinforaverylongwaitwhileevery *EEPROMreadfails
*/
ret_val = igc_read_nvm_eerd(hw, 0, 1, &nvm_data); if (ret_val) {
hw_dbg("EEPROM read failed\n"); goto out;
}
ret_val = hw->nvm.ops.acquire(hw); if (ret_val) goto out;
/* Do not use hw->nvm.ops.write, hw->nvm.ops.read *becausewedonotwanttotakethesynchronization *semaphorestwicehere.
*/
for (i = 0; i < NVM_CHECKSUM_REG; i++) {
ret_val = igc_read_nvm_eerd(hw, i, 1, &nvm_data); if (ret_val) {
hw->nvm.ops.release(hw);
hw_dbg("NVM Read Error while updating checksum.\n"); goto out;
}
checksum += nvm_data;
}
checksum = (u16)NVM_SUM - checksum;
ret_val = igc_write_nvm_srwr(hw, NVM_CHECKSUM_REG, 1,
&checksum); if (ret_val) {
hw->nvm.ops.release(hw);
hw_dbg("NVM Write Error while updating checksum.\n"); goto out;
}
/* This bit should not be set in normal operation. */ if (eee_su & IGC_EEE_SU_LPI_CLK_STP)
hw_dbg("LPI Clock Stop Bit should not be set!\n");
} else {
ipcnfg &= ~(IGC_IPCNFG_EEE_2_5G_AN | IGC_IPCNFG_EEE_1G_AN |
IGC_IPCNFG_EEE_100M_AN);
eeer &= ~(IGC_EEER_TX_LPI_EN | IGC_EEER_RX_LPI_EN |
IGC_EEER_LPI_FC);
}
wr32(IGC_IPCNFG, ipcnfg);
wr32(IGC_EEER, eeer);
rd32(IGC_IPCNFG);
rd32(IGC_EEER);
/* If we do not have link, LTR thresholds are zero. */ if (link) {
hw->mac.ops.get_speed_and_duplex(hw, &speed, &duplex);
/* Check if using copper interface with EEE enabled or if the *linkspeedis10Mbps.
*/ if (hw->dev_spec._base.eee_enable &&
speed != SPEED_10) { /* EEE enabled, so send LTRMAX threshold. */
ltrc = rd32(IGC_LTRC) |
IGC_LTRC_EEEMS_EN;
wr32(IGC_LTRC, ltrc);
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.14Bemerkung:
(vorverarbeitet am 2026-10-04)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.