lib.c
来自「linux 内核源代码」· C语言 代码 · 共 2,342 行 · 第 1/5 页
C
2,342 行
/** * e1000e_read_nvm_spi - Read EEPROM's using SPI * @hw: pointer to the HW structure * @offset: offset of word in the EEPROM to read * @words: number of words to read * @data: word read from the EEPROM * * Reads a 16 bit word from the EEPROM. **/s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data){ struct e1000_nvm_info *nvm = &hw->nvm; u32 i = 0; s32 ret_val; u16 word_in; u8 read_opcode = NVM_READ_OPCODE_SPI; /* A check for invalid values: offset too large, too many words, * and not enough words. */ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || (words == 0)) { hw_dbg(hw, "nvm parameter(s) out of bounds\n"); return -E1000_ERR_NVM; } ret_val = nvm->ops.acquire_nvm(hw); if (ret_val) return ret_val; ret_val = e1000_ready_nvm_eeprom(hw); if (ret_val) { nvm->ops.release_nvm(hw); return ret_val; } e1000_standby_nvm(hw); if ((nvm->address_bits == 8) && (offset >= 128)) read_opcode |= NVM_A8_OPCODE_SPI; /* Send the READ command (opcode + addr) */ e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits); /* Read the data. SPI NVMs increment the address with each byte * read and will roll over if reading beyond the end. This allows * us to read the whole NVM from any offset */ for (i = 0; i < words; i++) { word_in = e1000_shift_in_eec_bits(hw, 16); data[i] = (word_in >> 8) | (word_in << 8); } nvm->ops.release_nvm(hw); return 0;}/** * e1000e_read_nvm_eerd - Reads EEPROM using EERD register * @hw: pointer to the HW structure * @offset: offset of word in the EEPROM to read * @words: number of words to read * @data: word read from the EEPROM * * Reads a 16 bit word from the EEPROM using the EERD register. **/s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data){ struct e1000_nvm_info *nvm = &hw->nvm; u32 i, eerd = 0; s32 ret_val = 0; /* A check for invalid values: offset too large, too many words, * and not enough words. */ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || (words == 0)) { hw_dbg(hw, "nvm parameter(s) out of bounds\n"); return -E1000_ERR_NVM; } for (i = 0; i < words; i++) { eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + E1000_NVM_RW_REG_START; ew32(EERD, eerd); ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); if (ret_val) break; data[i] = (er32(EERD) >> E1000_NVM_RW_REG_DATA); } return ret_val;}/** * e1000e_write_nvm_spi - Write to EEPROM using SPI * @hw: pointer to the HW structure * @offset: offset within the EEPROM to be written to * @words: number of words to write * @data: 16 bit word(s) to be written to the EEPROM * * Writes data to EEPROM at offset using SPI interface. * * If e1000e_update_nvm_checksum is not called after this function , the * EEPROM will most likley contain an invalid checksum. **/s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data){ struct e1000_nvm_info *nvm = &hw->nvm; s32 ret_val; u16 widx = 0; /* A check for invalid values: offset too large, too many words, * and not enough words. */ if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || (words == 0)) { hw_dbg(hw, "nvm parameter(s) out of bounds\n"); return -E1000_ERR_NVM; } ret_val = nvm->ops.acquire_nvm(hw); if (ret_val) return ret_val; msleep(10); while (widx < words) { u8 write_opcode = NVM_WRITE_OPCODE_SPI; ret_val = e1000_ready_nvm_eeprom(hw); if (ret_val) { nvm->ops.release_nvm(hw); return ret_val; } e1000_standby_nvm(hw); /* Send the WRITE ENABLE command (8 bit opcode) */ e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, nvm->opcode_bits); e1000_standby_nvm(hw); /* Some SPI eeproms use the 8th address bit embedded in the * opcode */ if ((nvm->address_bits == 8) && (offset >= 128)) write_opcode |= NVM_A8_OPCODE_SPI; /* Send the Write command (8-bit opcode + addr) */ e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), nvm->address_bits); /* Loop to allow for up to whole page write of eeprom */ while (widx < words) { u16 word_out = data[widx]; word_out = (word_out >> 8) | (word_out << 8); e1000_shift_out_eec_bits(hw, word_out, 16); widx++; if ((((offset + widx) * 2) % nvm->page_size) == 0) { e1000_standby_nvm(hw); break; } } } msleep(10); return 0;}/** * e1000e_read_mac_addr - Read device MAC address * @hw: pointer to the HW structure * * Reads the device MAC address from the EEPROM and stores the value. * Since devices with two ports use the same EEPROM, we increment the * last bit in the MAC address for the second port. **/s32 e1000e_read_mac_addr(struct e1000_hw *hw){ s32 ret_val; u16 offset, nvm_data, i; for (i = 0; i < ETH_ALEN; i += 2) { offset = i >> 1; ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data); if (ret_val) { hw_dbg(hw, "NVM Read Error\n"); return ret_val; } hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); } /* Flip last bit of mac address if we're on second port */ if (hw->bus.func == E1000_FUNC_1) hw->mac.perm_addr[5] ^= 1; for (i = 0; i < ETH_ALEN; i++) hw->mac.addr[i] = hw->mac.perm_addr[i]; return 0;}/** * e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum * @hw: pointer to the HW structure * * Calculates the EEPROM checksum by reading/adding each word of the EEPROM * and then verifies that the sum of the EEPROM is equal to 0xBABA. **/s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw){ s32 ret_val; u16 checksum = 0; u16 i, nvm_data; for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { ret_val = e1000_read_nvm(hw, i, 1, &nvm_data); if (ret_val) { hw_dbg(hw, "NVM Read Error\n"); return ret_val; } checksum += nvm_data; } if (checksum != (u16) NVM_SUM) { hw_dbg(hw, "NVM Checksum Invalid\n"); return -E1000_ERR_NVM; } return 0;}/** * e1000e_update_nvm_checksum_generic - Update EEPROM checksum * @hw: pointer to the HW structure * * Updates the EEPROM checksum by reading/adding each word of the EEPROM * up to the checksum. Then calculates the EEPROM checksum and writes the * value to the EEPROM. **/s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw){ s32 ret_val; u16 checksum = 0; u16 i, nvm_data; for (i = 0; i < NVM_CHECKSUM_REG; i++) { ret_val = e1000_read_nvm(hw, i, 1, &nvm_data); if (ret_val) { hw_dbg(hw, "NVM Read Error while updating checksum.\n"); return ret_val; } checksum += nvm_data; } checksum = (u16) NVM_SUM - checksum; ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum); if (ret_val) hw_dbg(hw, "NVM Write Error while updating checksum.\n"); return ret_val;}/** * e1000e_reload_nvm - Reloads EEPROM * @hw: pointer to the HW structure * * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the * extended control register. **/void e1000e_reload_nvm(struct e1000_hw *hw){ u32 ctrl_ext; udelay(10); ctrl_ext = er32(CTRL_EXT); ctrl_ext |= E1000_CTRL_EXT_EE_RST; ew32(CTRL_EXT, ctrl_ext); e1e_flush();}/** * e1000_calculate_checksum - Calculate checksum for buffer * @buffer: pointer to EEPROM * @length: size of EEPROM to calculate a checksum for * * Calculates the checksum for some buffer on a specified length. The * checksum calculated is returned. **/static u8 e1000_calculate_checksum(u8 *buffer, u32 length){ u32 i; u8 sum = 0; if (!buffer) return 0; for (i = 0; i < length; i++) sum += buffer[i]; return (u8) (0 - sum);}/** * e1000_mng_enable_host_if - Checks host interface is enabled * @hw: pointer to the HW structure * * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND * * This function checks whether the HOST IF is enabled for command operaton * and also checks whether the previous command is completed. It busy waits * in case of previous command is not completed. **/static s32 e1000_mng_enable_host_if(struct e1000_hw *hw){ u32 hicr; u8 i; /* Check that the host interface is enabled. */ hicr = er32(HICR); if ((hicr & E1000_HICR_EN) == 0) { hw_dbg(hw, "E1000_HOST_EN bit disabled.\n"); return -E1000_ERR_HOST_INTERFACE_COMMAND; } /* check the previous command is completed */ for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { hicr = er32(HICR); if (!(hicr & E1000_HICR_C)) break; mdelay(1); } if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { hw_dbg(hw, "Previous command timeout failed .\n"); return -E1000_ERR_HOST_INTERFACE_COMMAND; } return 0;}/** * e1000e_check_mng_mode - check managament mode * @hw: pointer to the HW structure * * Reads the firmware semaphore register and returns true (>0) if * manageability is enabled, else false (0). **/bool e1000e_check_mng_mode(struct e1000_hw *hw){ u32 fwsm = er32(FWSM); return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;}/** * e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX * @hw: pointer to the HW structure * * Enables packet filtering on transmit packets if manageability is enabled * and host interface is enabled. **/bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw){ struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; u32 *buffer = (u32 *)&hw->mng_cookie; u32 offset; s32 ret_val, hdr_csum, csum; u8 i, len; /* No manageability, no filtering */ if (!e1000e_check_mng_mode(hw)) { hw->mac.tx_pkt_filtering = 0; return 0; } /* If we can't read from the host interface for whatever * reason, disable filtering. */ ret_val = e1000_mng_enable_host_if(hw); if (ret_val != 0) { hw->mac.tx_pkt_filtering = 0; return ret_val; } /* Read in the header. Length and offset are in dwords. */ len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; for (i = 0; i < len; i++) *(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i); hdr_csum = hdr->checksum; hdr->checksum = 0; csum = e1000_calculate_checksum((u8 *)hdr, E1000_MNG_DHCP_COOKIE_LENGTH); /* If either the checksums or signature don't match, then * the cookie area isn't considered valid, in which case we * take the safe route of assuming Tx filtering is enabled. */ if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) { hw->mac.tx_pkt_filtering = 1; return 1; } /* Cookie area is valid, make the final check for filtering. */ if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) { hw->mac.tx_pkt_filtering = 0; return 0; } hw->mac.tx_pkt_filtering = 1; return 1;}/** * e1000_mng_write_cmd_header - Writes manageability command header * @hw: pointer to the HW structure * @hdr: pointer to the host interface command header * * Writes the command header after does the checksum calculation. **/static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw, struct e1000_host_mng_command_header *hdr){ u16 i, length = sizeof(struct e1000_host_mng_command_header); /* Write the whole command header structure with new checksum. */ hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); length >>= 2; /* Write the relevant command block into the ram area. */ for (i = 0; i < length; i++) { E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i, *((u32 *) hdr + i)); e1e_flush(); } return 0;}/** * e1000_mng_host_if_write - Writes to the manageability host interface * @hw: pointer to the HW structure * @buffer: pointer to the host interface buffer * @length: size of the buffer * @offset: location in the buffer to write to * @sum: sum of the data (not checksum) * * This function writes the buffer content at the offset given on the host if. * It also does alignment considerations to do the writes in most efficient * way. Also fills up the sum of the buffer in *buffer parameter. **/static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer, u16 length, u16 offset, u8 *sum){ u8 *tmp; u8 *bufptr = buffer; u32 data = 0; u16 remaining, i, j, prev_bytes; /* sum = only sum of the data and it is not checksum */ if (length == 0 || offset +
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?