61b7a046e2
Since firmware does not use the semaphore between software and firmware.
Remove useless unilateral semaphore setting.
Fixes: 35c90ecccf
("net/txgbe: add EEPROM functions")
Cc: stable@dpdk.org
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
460 lines
10 KiB
C
460 lines
10 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright(c) 2015-2020 Beijing WangXun Technology Co., Ltd.
|
|
* Copyright(c) 2010-2017 Intel Corporation
|
|
*/
|
|
|
|
#include "txgbe_hw.h"
|
|
#include "txgbe_mng.h"
|
|
#include "txgbe_eeprom.h"
|
|
|
|
/**
|
|
* txgbe_init_eeprom_params - Initialize EEPROM params
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Initializes the EEPROM parameters txgbe_rom_info within the
|
|
* txgbe_hw struct in order to set up EEPROM access.
|
|
**/
|
|
s32 txgbe_init_eeprom_params(struct txgbe_hw *hw)
|
|
{
|
|
struct txgbe_rom_info *eeprom = &hw->rom;
|
|
u32 eec;
|
|
u16 eeprom_size;
|
|
int err = 0;
|
|
|
|
if (eeprom->type != txgbe_eeprom_unknown)
|
|
return 0;
|
|
|
|
eeprom->type = txgbe_eeprom_none;
|
|
/* Set default semaphore delay to 10ms which is a well
|
|
* tested value
|
|
*/
|
|
eeprom->semaphore_delay = 10; /*ms*/
|
|
/* Clear EEPROM page size, it will be initialized as needed */
|
|
eeprom->word_page_size = 0;
|
|
|
|
/*
|
|
* Check for EEPROM present first.
|
|
* If not present leave as none
|
|
*/
|
|
eec = rd32(hw, TXGBE_SPISTAT);
|
|
if (!(eec & TXGBE_SPISTAT_BPFLASH)) {
|
|
eeprom->type = txgbe_eeprom_flash;
|
|
|
|
/*
|
|
* SPI EEPROM is assumed here. This code would need to
|
|
* change if a future EEPROM is not SPI.
|
|
*/
|
|
eeprom_size = 4096;
|
|
eeprom->word_size = eeprom_size >> 1;
|
|
}
|
|
|
|
eeprom->address_bits = 16;
|
|
|
|
err = eeprom->read32(hw, TXGBE_SW_REGION_PTR << 1, &eeprom->sw_addr);
|
|
if (err) {
|
|
DEBUGOUT("EEPROM read failed.");
|
|
return err;
|
|
}
|
|
|
|
DEBUGOUT("eeprom params: type = %d, size = %d, address bits: %d %d",
|
|
eeprom->type, eeprom->word_size,
|
|
eeprom->address_bits, eeprom->sw_addr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* txgbe_get_eeprom_semaphore - Get hardware semaphore
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Sets the hardware semaphores so EEPROM access can occur for bit-bang method
|
|
**/
|
|
s32 txgbe_get_eeprom_semaphore(struct txgbe_hw *hw)
|
|
{
|
|
s32 status = TXGBE_ERR_EEPROM;
|
|
u32 timeout = 2000;
|
|
u32 i;
|
|
u32 swsm;
|
|
|
|
/* Get SMBI software semaphore between device drivers first */
|
|
for (i = 0; i < timeout; i++) {
|
|
/*
|
|
* If the SMBI bit is 0 when we read it, then the bit will be
|
|
* set and we have the semaphore
|
|
*/
|
|
swsm = rd32(hw, TXGBE_SWSEM);
|
|
if (!(swsm & TXGBE_SWSEM_PF)) {
|
|
status = 0;
|
|
break;
|
|
}
|
|
usec_delay(50);
|
|
}
|
|
|
|
if (i == timeout) {
|
|
DEBUGOUT("Driver can't access the eeprom - SMBI Semaphore not granted.");
|
|
/*
|
|
* this release is particularly important because our attempts
|
|
* above to get the semaphore may have succeeded, and if there
|
|
* was a timeout, we should unconditionally clear the semaphore
|
|
* bits to free the driver to make progress
|
|
*/
|
|
txgbe_release_eeprom_semaphore(hw);
|
|
|
|
usec_delay(50);
|
|
/*
|
|
* one last try
|
|
* If the SMBI bit is 0 when we read it, then the bit will be
|
|
* set and we have the semaphore
|
|
*/
|
|
swsm = rd32(hw, TXGBE_SWSEM);
|
|
if (!(swsm & TXGBE_SWSEM_PF))
|
|
status = 0;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* txgbe_release_eeprom_semaphore - Release hardware semaphore
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* This function clears hardware semaphore bits.
|
|
**/
|
|
void txgbe_release_eeprom_semaphore(struct txgbe_hw *hw)
|
|
{
|
|
wr32m(hw, TXGBE_SWSEM, TXGBE_SWSEM_PF, 0);
|
|
txgbe_flush(hw);
|
|
}
|
|
|
|
/**
|
|
* txgbe_ee_read - Read EEPROM word using a host interface cmd
|
|
* @hw: pointer to hardware structure
|
|
* @offset: offset of word in the EEPROM to read
|
|
* @data: word read from the EEPROM
|
|
*
|
|
* Reads a 16 bit word from the EEPROM using the hostif.
|
|
**/
|
|
s32 txgbe_ee_read16(struct txgbe_hw *hw, u32 offset,
|
|
u16 *data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
u32 addr = (offset << 1);
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
err = txgbe_hic_sr_read(hw, addr, (u8 *)data, 2);
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_ee_readw_buffer- Read EEPROM word(s) using hostif
|
|
* @hw: pointer to hardware structure
|
|
* @offset: offset of word in the EEPROM to read
|
|
* @words: number of words
|
|
* @data: word(s) read from the EEPROM
|
|
*
|
|
* Reads a 16 bit word(s) from the EEPROM using the hostif.
|
|
**/
|
|
s32 txgbe_ee_readw_buffer(struct txgbe_hw *hw,
|
|
u32 offset, u32 words, void *data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
u32 addr = (offset << 1);
|
|
u32 len = (words << 1);
|
|
u8 *buf = (u8 *)data;
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
while (len) {
|
|
u32 seg = (len <= TXGBE_PMMBX_DATA_SIZE
|
|
? len : TXGBE_PMMBX_DATA_SIZE);
|
|
|
|
err = txgbe_hic_sr_read(hw, addr, buf, seg);
|
|
if (err)
|
|
break;
|
|
|
|
len -= seg;
|
|
addr += seg;
|
|
buf += seg;
|
|
}
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
return err;
|
|
}
|
|
|
|
|
|
s32 txgbe_ee_readw_sw(struct txgbe_hw *hw, u32 offset,
|
|
u16 *data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
u32 addr = hw->rom.sw_addr + (offset << 1);
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
err = txgbe_hic_sr_read(hw, addr, (u8 *)data, 2);
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_ee_read32 - Read EEPROM word using a host interface cmd
|
|
* @hw: pointer to hardware structure
|
|
* @offset: offset of word in the EEPROM to read
|
|
* @data: word read from the EEPROM
|
|
*
|
|
* Reads a 32 bit word from the EEPROM using the hostif.
|
|
**/
|
|
s32 txgbe_ee_read32(struct txgbe_hw *hw, u32 addr, u32 *data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
err = txgbe_hic_sr_read(hw, addr, (u8 *)data, 4);
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_ee_write - Write EEPROM word using hostif
|
|
* @hw: pointer to hardware structure
|
|
* @offset: offset of word in the EEPROM to write
|
|
* @data: word write to the EEPROM
|
|
*
|
|
* Write a 16 bit word to the EEPROM using the hostif.
|
|
**/
|
|
s32 txgbe_ee_write16(struct txgbe_hw *hw, u32 offset,
|
|
u16 data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
u32 addr = (offset << 1);
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
err = txgbe_hic_sr_write(hw, addr, (u8 *)&data, 2);
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_ee_writew_buffer - Write EEPROM word(s) using hostif
|
|
* @hw: pointer to hardware structure
|
|
* @offset: offset of word in the EEPROM to write
|
|
* @words: number of words
|
|
* @data: word(s) write to the EEPROM
|
|
*
|
|
* Write a 16 bit word(s) to the EEPROM using the hostif.
|
|
**/
|
|
s32 txgbe_ee_writew_buffer(struct txgbe_hw *hw,
|
|
u32 offset, u32 words, void *data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
u32 addr = (offset << 1);
|
|
u32 len = (words << 1);
|
|
u8 *buf = (u8 *)data;
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
while (len) {
|
|
u32 seg = (len <= TXGBE_PMMBX_DATA_SIZE
|
|
? len : TXGBE_PMMBX_DATA_SIZE);
|
|
|
|
err = txgbe_hic_sr_write(hw, addr, buf, seg);
|
|
if (err)
|
|
break;
|
|
|
|
len -= seg;
|
|
buf += seg;
|
|
}
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
return err;
|
|
}
|
|
|
|
s32 txgbe_ee_writew_sw(struct txgbe_hw *hw, u32 offset,
|
|
u16 data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
u32 addr = hw->rom.sw_addr + (offset << 1);
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
err = txgbe_hic_sr_write(hw, addr, (u8 *)&data, 2);
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_ee_write32 - Read EEPROM word using a host interface cmd
|
|
* @hw: pointer to hardware structure
|
|
* @offset: offset of word in the EEPROM to read
|
|
* @data: word read from the EEPROM
|
|
*
|
|
* Reads a 32 bit word from the EEPROM using the hostif.
|
|
**/
|
|
s32 txgbe_ee_write32(struct txgbe_hw *hw, u32 addr, u32 data)
|
|
{
|
|
const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH;
|
|
int err;
|
|
|
|
err = hw->mac.acquire_swfw_sync(hw, mask);
|
|
if (err)
|
|
return err;
|
|
|
|
err = txgbe_hic_sr_write(hw, addr, (u8 *)&data, 4);
|
|
|
|
hw->mac.release_swfw_sync(hw, mask);
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_calc_eeprom_checksum - Calculates and returns the checksum
|
|
* @hw: pointer to hardware structure
|
|
*
|
|
* Returns a negative error code on error, or the 16-bit checksum
|
|
**/
|
|
#define BUFF_SIZE 64
|
|
s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw)
|
|
{
|
|
u16 checksum = 0, read_checksum = 0;
|
|
int i, j, seg;
|
|
int err;
|
|
u16 buffer[BUFF_SIZE];
|
|
|
|
err = hw->rom.readw_sw(hw, TXGBE_EEPROM_CHECKSUM, &read_checksum);
|
|
if (err) {
|
|
DEBUGOUT("EEPROM read failed");
|
|
return err;
|
|
}
|
|
|
|
for (i = 0; i < TXGBE_EE_CSUM_MAX; i += seg) {
|
|
seg = (i + BUFF_SIZE < TXGBE_EE_CSUM_MAX
|
|
? BUFF_SIZE : TXGBE_EE_CSUM_MAX - i);
|
|
err = hw->rom.readw_buffer(hw, i, seg, buffer);
|
|
if (err)
|
|
return err;
|
|
for (j = 0; j < seg; j++)
|
|
checksum += buffer[j];
|
|
}
|
|
|
|
checksum = (u16)TXGBE_EEPROM_SUM - checksum + read_checksum;
|
|
|
|
return (s32)checksum;
|
|
}
|
|
|
|
/**
|
|
* txgbe_validate_eeprom_checksum - Validate EEPROM checksum
|
|
* @hw: pointer to hardware structure
|
|
* @checksum_val: calculated checksum
|
|
*
|
|
* Performs checksum calculation and validates the EEPROM checksum. If the
|
|
* caller does not need checksum_val, the value can be NULL.
|
|
**/
|
|
s32 txgbe_validate_eeprom_checksum(struct txgbe_hw *hw,
|
|
u16 *checksum_val)
|
|
{
|
|
u16 checksum;
|
|
u16 read_checksum = 0;
|
|
int err;
|
|
|
|
/* Read the first word from the EEPROM. If this times out or fails, do
|
|
* not continue or we could be in for a very long wait while every
|
|
* EEPROM read fails
|
|
*/
|
|
err = hw->rom.read16(hw, 0, &checksum);
|
|
if (err) {
|
|
DEBUGOUT("EEPROM read failed");
|
|
return err;
|
|
}
|
|
|
|
err = hw->rom.calc_checksum(hw);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
checksum = (u16)(err & 0xffff);
|
|
|
|
err = hw->rom.readw_sw(hw, TXGBE_EEPROM_CHECKSUM, &read_checksum);
|
|
if (err) {
|
|
DEBUGOUT("EEPROM read failed");
|
|
return err;
|
|
}
|
|
|
|
/* Verify read checksum from EEPROM is the same as
|
|
* calculated checksum
|
|
*/
|
|
if (read_checksum != checksum) {
|
|
err = TXGBE_ERR_EEPROM_CHECKSUM;
|
|
DEBUGOUT("EEPROM checksum error");
|
|
}
|
|
|
|
/* If the user cares, return the calculated checksum */
|
|
if (checksum_val)
|
|
*checksum_val = checksum;
|
|
|
|
return err;
|
|
}
|
|
|
|
/**
|
|
* txgbe_update_eeprom_checksum - Updates the EEPROM checksum
|
|
* @hw: pointer to hardware structure
|
|
**/
|
|
s32 txgbe_update_eeprom_checksum(struct txgbe_hw *hw)
|
|
{
|
|
s32 status;
|
|
u16 checksum;
|
|
|
|
/* Read the first word from the EEPROM. If this times out or fails, do
|
|
* not continue or we could be in for a very long wait while every
|
|
* EEPROM read fails
|
|
*/
|
|
status = hw->rom.read16(hw, 0, &checksum);
|
|
if (status) {
|
|
DEBUGOUT("EEPROM read failed");
|
|
return status;
|
|
}
|
|
|
|
status = hw->rom.calc_checksum(hw);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
checksum = (u16)(status & 0xffff);
|
|
|
|
status = hw->rom.writew_sw(hw, TXGBE_EEPROM_CHECKSUM, checksum);
|
|
|
|
return status;
|
|
}
|
|
|