From: Jiawen Wu Date: Mon, 19 Oct 2020 08:53:24 +0000 (+0800) Subject: net/txgbe: add EEPROM functions X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=35c90ecccfd4;p=dpdk.git net/txgbe: add EEPROM functions Add EEPROM functions. Signed-off-by: Jiawen Wu Reviewed-by: Ferruh Yigit --- diff --git a/drivers/net/txgbe/base/meson.build b/drivers/net/txgbe/base/meson.build index 54d6e399dd..9755bbbb40 100644 --- a/drivers/net/txgbe/base/meson.build +++ b/drivers/net/txgbe/base/meson.build @@ -2,7 +2,9 @@ # Copyright(c) 2015-2020 sources = [ + 'txgbe_eeprom.c', 'txgbe_hw.c', + 'txgbe_mng.c', ] error_cflags = [] diff --git a/drivers/net/txgbe/base/txgbe.h b/drivers/net/txgbe/base/txgbe.h index 7783bd6941..329764be03 100644 --- a/drivers/net/txgbe/base/txgbe.h +++ b/drivers/net/txgbe/base/txgbe.h @@ -6,6 +6,8 @@ #define _TXGBE_H_ #include "txgbe_type.h" +#include "txgbe_mng.h" +#include "txgbe_eeprom.h" #include "txgbe_hw.h" #endif /* _TXGBE_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_eeprom.c b/drivers/net/txgbe/base/txgbe_eeprom.c new file mode 100644 index 0000000000..72cd3ff307 --- /dev/null +++ b/drivers/net/txgbe/base/txgbe_eeprom.c @@ -0,0 +1,581 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2015-2020 + */ + +#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; + + DEBUGFUNC("txgbe_init_eeprom_params"); + + 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.\n"); + return err; + } + + DEBUGOUT("eeprom params: type = %d, size = %d, address bits: " + "%d %d\n", 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; + + DEBUGFUNC("txgbe_get_eeprom_semaphore"); + + + /* 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.\n"); + /* + * 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; + } + + /* Now get the semaphore between SW/FW through the SWESMBI bit */ + if (status == 0) { + for (i = 0; i < timeout; i++) { + /* Set the SW EEPROM semaphore bit to request access */ + wr32m(hw, TXGBE_MNGSWSYNC, + TXGBE_MNGSWSYNC_REQ, TXGBE_MNGSWSYNC_REQ); + + /* + * If we set the bit successfully then we got the + * semaphore. + */ + swsm = rd32(hw, TXGBE_MNGSWSYNC); + if (swsm & TXGBE_MNGSWSYNC_REQ) + break; + + usec_delay(50); + } + + /* + * Release semaphores and return error if SW EEPROM semaphore + * was not granted because we don't have access to the EEPROM + */ + if (i >= timeout) { + DEBUGOUT("SWESMBI Software EEPROM semaphore not granted.\n"); + txgbe_release_eeprom_semaphore(hw); + status = TXGBE_ERR_EEPROM; + } + } else { + DEBUGOUT("Software semaphore SMBI between device drivers " + "not granted.\n"); + } + + 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) +{ + DEBUGFUNC("txgbe_release_eeprom_semaphore"); + + wr32m(hw, TXGBE_MNGSWSYNC, TXGBE_MNGSWSYNC_REQ, 0); + 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_read_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_read_buffer - Read EEPROM byte(s) using hostif + * @hw: pointer to hardware structure + * @addr: offset of bytes in the EEPROM to read + * @len: number of bytes + * @data: byte(s) read from the EEPROM + * + * Reads a 8 bit byte(s) from the EEPROM using the hostif. + **/ +s32 txgbe_ee_read_buffer(struct txgbe_hw *hw, + u32 addr, u32 len, void *data) +{ + const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH; + 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; + buf += seg; + } + + 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; + + DEBUGFUNC("\n"); + + 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_write_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; + + DEBUGFUNC("\n"); + + 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_ee_write_buffer - Write EEPROM byte(s) using hostif + * @hw: pointer to hardware structure + * @addr: offset of bytes in the EEPROM to write + * @len: number of bytes + * @data: word(s) write to the EEPROM + * + * Write a 8 bit byte(s) to the EEPROM using the hostif. + **/ +s32 txgbe_ee_write_buffer(struct txgbe_hw *hw, + u32 addr, u32 len, void *data) +{ + const u32 mask = TXGBE_MNGSEM_SWMBX | TXGBE_MNGSEM_SWFLASH; + 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; +} + +/** + * 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]; + + DEBUGFUNC("txgbe_calc_eeprom_checksum"); + + err = hw->rom.readw_sw(hw, TXGBE_EEPROM_CHECKSUM, &read_checksum); + if (err) { + DEBUGOUT("EEPROM read failed\n"); + 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; + + DEBUGFUNC("txgbe_validate_eeprom_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 + */ + err = hw->rom.read16(hw, 0, &checksum); + if (err) { + DEBUGOUT("EEPROM read failed\n"); + 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\n"); + 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\n"); + } + + /* 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; + + DEBUGFUNC("txgbe_update_eeprom_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\n"); + 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; +} + diff --git a/drivers/net/txgbe/base/txgbe_eeprom.h b/drivers/net/txgbe/base/txgbe_eeprom.h new file mode 100644 index 0000000000..137fb1c302 --- /dev/null +++ b/drivers/net/txgbe/base/txgbe_eeprom.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2015-2020 + */ + +#ifndef _TXGBE_EEPROM_H_ +#define _TXGBE_EEPROM_H_ + +/* Checksum and EEPROM pointers */ +#define TXGBE_PBANUM_PTR_GUARD 0xFAFA +#define TXGBE_EEPROM_SUM 0xBABA + +#define TXGBE_FW_PTR 0x0F +#define TXGBE_PBANUM0_PTR 0x05 +#define TXGBE_PBANUM1_PTR 0x06 +#define TXGBE_SW_REGION_PTR 0x1C + +#define TXGBE_EE_CSUM_MAX 0x800 +#define TXGBE_EEPROM_CHECKSUM 0x2F + +#define TXGBE_SAN_MAC_ADDR_PTR 0x18 +#define TXGBE_DEVICE_CAPS 0x1C +#define TXGBE_EEPROM_VERSION_L 0x1D +#define TXGBE_EEPROM_VERSION_H 0x1E +#define TXGBE_ISCSI_BOOT_CONFIG 0x07 + + +s32 txgbe_init_eeprom_params(struct txgbe_hw *hw); +s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw); +s32 txgbe_validate_eeprom_checksum(struct txgbe_hw *hw, u16 *checksum_val); +s32 txgbe_update_eeprom_checksum(struct txgbe_hw *hw); +s32 txgbe_get_eeprom_semaphore(struct txgbe_hw *hw); +void txgbe_release_eeprom_semaphore(struct txgbe_hw *hw); + +s32 txgbe_ee_read16(struct txgbe_hw *hw, u32 offset, u16 *data); +s32 txgbe_ee_readw_sw(struct txgbe_hw *hw, u32 offset, u16 *data); +s32 txgbe_ee_readw_buffer(struct txgbe_hw *hw, u32 offset, u32 words, + void *data); +s32 txgbe_ee_read32(struct txgbe_hw *hw, u32 addr, u32 *data); +s32 txgbe_ee_read_buffer(struct txgbe_hw *hw, u32 addr, u32 len, void *data); + +s32 txgbe_ee_write16(struct txgbe_hw *hw, u32 offset, u16 data); +s32 txgbe_ee_writew_sw(struct txgbe_hw *hw, u32 offset, u16 data); +s32 txgbe_ee_writew_buffer(struct txgbe_hw *hw, u32 offset, u32 words, + void *data); +s32 txgbe_ee_write32(struct txgbe_hw *hw, u32 addr, u32 data); +s32 txgbe_ee_write_buffer(struct txgbe_hw *hw, u32 addr, u32 len, void *data); + + +#endif /* _TXGBE_EEPROM_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index 6478b6fbfe..e942c5631d 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -3,6 +3,7 @@ */ #include "txgbe_type.h" +#include "txgbe_eeprom.h" #include "txgbe_hw.h" #define TXGBE_RAPTOR_RAR_ENTRIES 128 @@ -135,13 +136,29 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) { struct txgbe_bus_info *bus = &hw->bus; struct txgbe_mac_info *mac = &hw->mac; + struct txgbe_rom_info *rom = &hw->rom; DEBUGFUNC("txgbe_init_ops_pf"); /* BUS */ bus->set_lan_id = txgbe_set_lan_id_multi_port; + /* MAC */ mac->num_rar_entries = TXGBE_RAPTOR_RAR_ENTRIES; + /* EEPROM */ + rom->init_params = txgbe_init_eeprom_params; + rom->read16 = txgbe_ee_read16; + rom->readw_buffer = txgbe_ee_readw_buffer; + rom->readw_sw = txgbe_ee_readw_sw; + rom->read32 = txgbe_ee_read32; + rom->write16 = txgbe_ee_write16; + rom->writew_buffer = txgbe_ee_writew_buffer; + rom->writew_sw = txgbe_ee_writew_sw; + rom->write32 = txgbe_ee_write32; + rom->validate_checksum = txgbe_validate_eeprom_checksum; + rom->update_checksum = txgbe_update_eeprom_checksum; + rom->calc_checksum = txgbe_calc_eeprom_checksum; + return 0; } diff --git a/drivers/net/txgbe/base/txgbe_mng.c b/drivers/net/txgbe/base/txgbe_mng.c new file mode 100644 index 0000000000..224e48f5e1 --- /dev/null +++ b/drivers/net/txgbe/base/txgbe_mng.c @@ -0,0 +1,396 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2015-2020 + */ + +#include "txgbe_type.h" +#include "txgbe_mng.h" + +/** + * txgbe_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 +txgbe_calculate_checksum(u8 *buffer, u32 length) +{ + u32 i; + u8 sum = 0; + + for (i = 0; i < length; i++) + sum += buffer[i]; + + return (u8)(0 - sum); +} + +/** + * txgbe_hic_unlocked - Issue command to manageability block unlocked + * @hw: pointer to the HW structure + * @buffer: command to write and where the return status will be placed + * @length: length of buffer, must be multiple of 4 bytes + * @timeout: time in ms to wait for command completion + * + * Communicates with the manageability block. On success return 0 + * else returns semaphore error when encountering an error acquiring + * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + * + * This function assumes that the TXGBE_MNGSEM_SWMBX semaphore is held + * by the caller. + **/ +static s32 +txgbe_hic_unlocked(struct txgbe_hw *hw, u32 *buffer, u32 length, u32 timeout) +{ + u32 value, loop; + u16 i, dword_len; + + DEBUGFUNC("txgbe_hic_unlocked"); + + if (!length || length > TXGBE_PMMBX_BSIZE) { + DEBUGOUT("Buffer length failure buffersize=%d.\n", length); + return TXGBE_ERR_HOST_INTERFACE_COMMAND; + } + + /* Calculate length in DWORDs. We must be DWORD aligned */ + if (length % sizeof(u32)) { + DEBUGOUT("Buffer length failure, not aligned to dword"); + return TXGBE_ERR_INVALID_ARGUMENT; + } + + dword_len = length >> 2; + + /* The device driver writes the relevant command block + * into the ram area. + */ + for (i = 0; i < dword_len; i++) { + wr32a(hw, TXGBE_MNGMBX, i, cpu_to_le32(buffer[i])); + buffer[i] = rd32a(hw, TXGBE_MNGMBX, i); + } + txgbe_flush(hw); + + /* Setting this bit tells the ARC that a new command is pending. */ + wr32m(hw, TXGBE_MNGMBXCTL, + TXGBE_MNGMBXCTL_SWRDY, TXGBE_MNGMBXCTL_SWRDY); + + /* Check command completion */ + loop = po32m(hw, TXGBE_MNGMBXCTL, + TXGBE_MNGMBXCTL_FWRDY, TXGBE_MNGMBXCTL_FWRDY, + &value, timeout, 1000); + if (!loop || !(value & TXGBE_MNGMBXCTL_FWACK)) { + DEBUGOUT("Command has failed with no status valid.\n"); + return TXGBE_ERR_HOST_INTERFACE_COMMAND; + } + + return 0; +} + +/** + * txgbe_host_interface_command - Issue command to manageability block + * @hw: pointer to the HW structure + * @buffer: contains the command to write and where the return status will + * be placed + * @length: length of buffer, must be multiple of 4 bytes + * @timeout: time in ms to wait for command completion + * @return_data: read and return data from the buffer (true) or not (false) + * Needed because FW structures are big endian and decoding of + * these fields can be 8 bit or 16 bit based on command. Decoding + * is not easily understood without making a table of commands. + * So we will leave this up to the caller to read back the data + * in these cases. + * + * Communicates with the manageability block. On success return 0 + * else returns semaphore error when encountering an error acquiring + * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +static s32 +txgbe_host_interface_command(struct txgbe_hw *hw, u32 *buffer, + u32 length, u32 timeout, bool return_data) +{ + u32 hdr_size = sizeof(struct txgbe_hic_hdr); + struct txgbe_hic_hdr *resp = (struct txgbe_hic_hdr *)buffer; + u16 buf_len; + s32 err; + u32 bi; + u32 dword_len; + + DEBUGFUNC("txgbe_host_interface_command"); + + if (length == 0 || length > TXGBE_PMMBX_BSIZE) { + DEBUGOUT("Buffer length failure buffersize=%d.\n", length); + return TXGBE_ERR_HOST_INTERFACE_COMMAND; + } + + /* Take management host interface semaphore */ + err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWMBX); + if (err) + return err; + + err = txgbe_hic_unlocked(hw, buffer, length, timeout); + if (err) + goto rel_out; + + if (!return_data) + goto rel_out; + + /* Calculate length in DWORDs */ + dword_len = hdr_size >> 2; + + /* first pull in the header so we know the buffer length */ + for (bi = 0; bi < dword_len; bi++) + buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi); + + /* + * If there is any thing in data position pull it in + * Read Flash command requires reading buffer length from + * two byes instead of one byte + */ + if (resp->cmd == 0x30) { + for (; bi < dword_len + 2; bi++) + buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi); + + buf_len = (((u16)(resp->cmd_or_resp.ret_status) << 3) + & 0xF00) | resp->buf_len; + hdr_size += (2 << 2); + } else { + buf_len = resp->buf_len; + } + if (!buf_len) + goto rel_out; + + if (length < buf_len + hdr_size) { + DEBUGOUT("Buffer not large enough for reply message.\n"); + err = TXGBE_ERR_HOST_INTERFACE_COMMAND; + goto rel_out; + } + + /* Calculate length in DWORDs, add 3 for odd lengths */ + dword_len = (buf_len + 3) >> 2; + + /* Pull in the rest of the buffer (bi is where we left off) */ + for (; bi <= dword_len; bi++) + buffer[bi] = rd32a(hw, TXGBE_MNGMBX, bi); + +rel_out: + hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWMBX); + + return err; +} + +/** + * txgbe_hic_sr_read - Read EEPROM word using a host interface cmd + * assuming that the semaphore is already obtained. + * @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_hic_sr_read(struct txgbe_hw *hw, u32 addr, u8 *buf, int len) +{ + struct txgbe_hic_read_shadow_ram command; + u32 value; + int err, i = 0, j = 0; + + if (len > TXGBE_PMMBX_DATA_SIZE) + return TXGBE_ERR_HOST_INTERFACE_COMMAND; + + memset(&command, 0, sizeof(command)); + command.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD; + command.hdr.req.buf_lenh = 0; + command.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN; + command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; + command.address = cpu_to_be32(addr); + command.length = cpu_to_be16(len); + + err = txgbe_hic_unlocked(hw, (u32 *)&command, + sizeof(command), TXGBE_HI_COMMAND_TIMEOUT); + if (err) + return err; + + while (i < (len >> 2)) { + value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i); + ((u32 *)buf)[i] = value; + i++; + } + + value = rd32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i); + for (i <<= 2; i < len; i++) + ((u8 *)buf)[i] = ((u8 *)&value)[j++]; + + return 0; +} + +/** + * txgbe_hic_sr_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_hic_sr_write(struct txgbe_hw *hw, u32 addr, u8 *buf, int len) +{ + struct txgbe_hic_write_shadow_ram command; + u32 value; + int err = 0, i = 0, j = 0; + + if (len > TXGBE_PMMBX_DATA_SIZE) + return TXGBE_ERR_HOST_INTERFACE_COMMAND; + + memset(&command, 0, sizeof(command)); + command.hdr.req.cmd = FW_WRITE_SHADOW_RAM_CMD; + command.hdr.req.buf_lenh = 0; + command.hdr.req.buf_lenl = FW_WRITE_SHADOW_RAM_LEN; + command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; + command.address = cpu_to_be32(addr); + command.length = cpu_to_be16(len); + + while (i < (len >> 2)) { + value = ((u32 *)buf)[i]; + wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + i, value); + i++; + } + + for (i <<= 2; i < len; i++) + ((u8 *)&value)[j++] = ((u8 *)buf)[i]; + + wr32a(hw, TXGBE_MNGMBX, FW_NVM_DATA_OFFSET + (i >> 2), value); + + UNREFERENCED_PARAMETER(&command); + + return err; +} + +/** + * txgbe_hic_set_drv_ver - Sends driver version to firmware + * @hw: pointer to the HW structure + * @maj: driver version major number + * @min: driver version minor number + * @build: driver version build number + * @sub: driver version sub build number + * @len: unused + * @driver_ver: unused + * + * Sends driver version number to firmware through the manageability + * block. On success return 0 + * else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring + * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +s32 txgbe_hic_set_drv_ver(struct txgbe_hw *hw, u8 maj, u8 min, + u8 build, u8 sub, u16 len, + const char *driver_ver) +{ + struct txgbe_hic_drv_info fw_cmd; + int i; + s32 ret_val = 0; + + DEBUGFUNC("txgbe_hic_set_drv_ver"); + UNREFERENCED_PARAMETER(len, driver_ver); + + fw_cmd.hdr.cmd = FW_CEM_CMD_DRIVER_INFO; + fw_cmd.hdr.buf_len = FW_CEM_CMD_DRIVER_INFO_LEN; + fw_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; + fw_cmd.port_num = (u8)hw->bus.func; + fw_cmd.ver_maj = maj; + fw_cmd.ver_min = min; + fw_cmd.ver_build = build; + fw_cmd.ver_sub = sub; + fw_cmd.hdr.checksum = 0; + fw_cmd.pad = 0; + fw_cmd.pad2 = 0; + fw_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&fw_cmd, + (FW_CEM_HDR_LEN + fw_cmd.hdr.buf_len)); + + for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { + ret_val = txgbe_host_interface_command(hw, (u32 *)&fw_cmd, + sizeof(fw_cmd), + TXGBE_HI_COMMAND_TIMEOUT, + true); + if (ret_val != 0) + continue; + + if (fw_cmd.hdr.cmd_or_resp.ret_status == + FW_CEM_RESP_STATUS_SUCCESS) + ret_val = 0; + else + ret_val = TXGBE_ERR_HOST_INTERFACE_COMMAND; + + break; + } + + return ret_val; +} + +/** + * txgbe_hic_reset - send reset cmd to fw + * @hw: pointer to hardware structure + * + * Sends reset cmd to firmware through the manageability + * block. On success return 0 + * else returns TXGBE_ERR_SWFW_SYNC when encountering an error acquiring + * semaphore or TXGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +s32 +txgbe_hic_reset(struct txgbe_hw *hw) +{ + struct txgbe_hic_reset reset_cmd; + int i; + s32 err = 0; + + DEBUGFUNC("\n"); + + reset_cmd.hdr.cmd = FW_RESET_CMD; + reset_cmd.hdr.buf_len = FW_RESET_LEN; + reset_cmd.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED; + reset_cmd.lan_id = hw->bus.lan_id; + reset_cmd.reset_type = (u16)hw->reset_type; + reset_cmd.hdr.checksum = 0; + reset_cmd.hdr.checksum = txgbe_calculate_checksum((u8 *)&reset_cmd, + (FW_CEM_HDR_LEN + reset_cmd.hdr.buf_len)); + + for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { + err = txgbe_host_interface_command(hw, (u32 *)&reset_cmd, + sizeof(reset_cmd), + TXGBE_HI_COMMAND_TIMEOUT, + true); + if (err != 0) + continue; + + if (reset_cmd.hdr.cmd_or_resp.ret_status == + FW_CEM_RESP_STATUS_SUCCESS) + err = 0; + else + err = TXGBE_ERR_HOST_INTERFACE_COMMAND; + + break; + } + + return err; +} + +/** + * txgbe_mng_present - returns true when management capability is present + * @hw: pointer to hardware structure + */ +bool +txgbe_mng_present(struct txgbe_hw *hw) +{ + if (hw->mac.type == txgbe_mac_unknown) + return false; + + return !!rd32m(hw, TXGBE_STAT, TXGBE_STAT_MNGINIT); +} + +/** + * txgbe_mng_enabled - Is the manageability engine enabled? + * @hw: pointer to hardware structure + * + * Returns true if the manageability engine is enabled. + **/ +bool +txgbe_mng_enabled(struct txgbe_hw *hw) +{ + UNREFERENCED_PARAMETER(hw); + /* firmware does not control laser */ + return false; +} diff --git a/drivers/net/txgbe/base/txgbe_mng.h b/drivers/net/txgbe/base/txgbe_mng.h new file mode 100644 index 0000000000..7514cc1e1e --- /dev/null +++ b/drivers/net/txgbe/base/txgbe_mng.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2015-2020 + */ + +#ifndef _TXGBE_MNG_H_ +#define _TXGBE_MNG_H_ + +#include "txgbe_type.h" + + +#define TXGBE_PMMBX_QSIZE 64 /* Num of dwords in range */ +#define TXGBE_PMMBX_BSIZE (TXGBE_PMMBX_QSIZE * 4) +#define TXGBE_PMMBX_DATA_SIZE (TXGBE_PMMBX_BSIZE - FW_NVM_DATA_OFFSET * 4) +#define TXGBE_HI_COMMAND_TIMEOUT 5000 /* Process HI command limit */ +#define TXGBE_HI_FLASH_ERASE_TIMEOUT 5000 /* Process Erase command limit */ +#define TXGBE_HI_FLASH_UPDATE_TIMEOUT 5000 /* Process Update command limit */ +#define TXGBE_HI_FLASH_VERIFY_TIMEOUT 60000 /* Process Apply command limit */ +#define TXGBE_HI_PHY_MGMT_REQ_TIMEOUT 2000 /* Wait up to 2 seconds */ + +/* CEM Support */ +#define FW_CEM_HDR_LEN 0x4 +#define FW_CEM_CMD_DRIVER_INFO 0xDD +#define FW_CEM_CMD_DRIVER_INFO_LEN 0x5 +#define FW_CEM_CMD_RESERVED 0X0 +#define FW_CEM_UNUSED_VER 0x0 +#define FW_CEM_MAX_RETRIES 3 +#define FW_CEM_RESP_STATUS_SUCCESS 0x1 +#define FW_READ_SHADOW_RAM_CMD 0x31 +#define FW_READ_SHADOW_RAM_LEN 0x6 +#define FW_WRITE_SHADOW_RAM_CMD 0x33 +#define FW_WRITE_SHADOW_RAM_LEN 0xA /* 8 plus 1 WORD to write */ +#define FW_SHADOW_RAM_DUMP_CMD 0x36 +#define FW_SHADOW_RAM_DUMP_LEN 0 +#define FW_DEFAULT_CHECKSUM 0xFF /* checksum always 0xFF */ +#define FW_NVM_DATA_OFFSET 3 +#define FW_MAX_READ_BUFFER_SIZE 244 +#define FW_DISABLE_RXEN_CMD 0xDE +#define FW_DISABLE_RXEN_LEN 0x1 +#define FW_PHY_MGMT_REQ_CMD 0x20 +#define FW_RESET_CMD 0xDF +#define FW_RESET_LEN 0x2 +#define FW_SETUP_MAC_LINK_CMD 0xE0 +#define FW_SETUP_MAC_LINK_LEN 0x2 +#define FW_FLASH_UPGRADE_START_CMD 0xE3 +#define FW_FLASH_UPGRADE_START_LEN 0x1 +#define FW_FLASH_UPGRADE_WRITE_CMD 0xE4 +#define FW_FLASH_UPGRADE_VERIFY_CMD 0xE5 +#define FW_FLASH_UPGRADE_VERIFY_LEN 0x4 +#define FW_PHY_ACT_DATA_COUNT 4 +#define FW_PHY_TOKEN_DELAY 5 /* milliseconds */ +#define FW_PHY_TOKEN_WAIT 5 /* seconds */ +#define FW_PHY_TOKEN_RETRIES ((FW_PHY_TOKEN_WAIT * 1000) / FW_PHY_TOKEN_DELAY) + +/* Host Interface Command Structures */ +struct txgbe_hic_hdr { + u8 cmd; + u8 buf_len; + union { + u8 cmd_resv; + u8 ret_status; + } cmd_or_resp; + u8 checksum; +}; + +struct txgbe_hic_hdr2_req { + u8 cmd; + u8 buf_lenh; + u8 buf_lenl; + u8 checksum; +}; + +struct txgbe_hic_hdr2_rsp { + u8 cmd; + u8 buf_lenl; + u8 buf_lenh_status; /* 7-5: high bits of buf_len, 4-0: status */ + u8 checksum; +}; + +union txgbe_hic_hdr2 { + struct txgbe_hic_hdr2_req req; + struct txgbe_hic_hdr2_rsp rsp; +}; + +struct txgbe_hic_drv_info { + struct txgbe_hic_hdr hdr; + u8 port_num; + u8 ver_sub; + u8 ver_build; + u8 ver_min; + u8 ver_maj; + u8 pad; /* end spacing to ensure length is mult. of dword */ + u16 pad2; /* end spacing to ensure length is mult. of dword2 */ +}; + +/* These need to be dword aligned */ +struct txgbe_hic_read_shadow_ram { + union txgbe_hic_hdr2 hdr; + u32 address; + u16 length; + u16 pad2; + u16 data; + u16 pad3; +}; + +struct txgbe_hic_write_shadow_ram { + union txgbe_hic_hdr2 hdr; + u32 address; + u16 length; + u16 pad2; + u16 data; + u16 pad3; +}; + +struct txgbe_hic_disable_rxen { + struct txgbe_hic_hdr hdr; + u8 port_number; + u8 pad2; + u16 pad3; +}; + +struct txgbe_hic_reset { + struct txgbe_hic_hdr hdr; + u16 lan_id; + u16 reset_type; +}; + +struct txgbe_hic_phy_cfg { + struct txgbe_hic_hdr hdr; + u8 lan_id; + u8 phy_mode; + u16 phy_speed; +}; + +enum txgbe_module_id { + TXGBE_MODULE_EEPROM = 0, + TXGBE_MODULE_FIRMWARE, + TXGBE_MODULE_HARDWARE, + TXGBE_MODULE_PCIE +}; + +struct txgbe_hic_upg_start { + struct txgbe_hic_hdr hdr; + u8 module_id; + u8 pad2; + u16 pad3; +}; + +struct txgbe_hic_upg_write { + struct txgbe_hic_hdr hdr; + u8 data_len; + u8 eof_flag; + u16 check_sum; + u32 data[62]; +}; + +enum txgbe_upg_flag { + TXGBE_RESET_NONE = 0, + TXGBE_RESET_FIRMWARE, + TXGBE_RELOAD_EEPROM, + TXGBE_RESET_LAN +}; + +struct txgbe_hic_upg_verify { + struct txgbe_hic_hdr hdr; + u32 action_flag; +}; + +s32 txgbe_hic_sr_read(struct txgbe_hw *hw, u32 addr, u8 *buf, int len); +s32 txgbe_hic_sr_write(struct txgbe_hw *hw, u32 addr, u8 *buf, int len); + +s32 txgbe_hic_set_drv_ver(struct txgbe_hw *hw, u8 maj, u8 min, u8 build, + u8 ver, u16 len, const char *str); +s32 txgbe_hic_reset(struct txgbe_hw *hw); +bool txgbe_mng_present(struct txgbe_hw *hw); +bool txgbe_mng_enabled(struct txgbe_hw *hw); +#endif /* _TXGBE_MNG_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index 87c2e1681c..c43c39e99b 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -13,6 +13,13 @@ #include "txgbe_osdep.h" #include "txgbe_devids.h" +enum txgbe_eeprom_type { + txgbe_eeprom_unknown = 0, + txgbe_eeprom_spi, + txgbe_eeprom_flash, + txgbe_eeprom_none /* No NVM support */ +}; + enum txgbe_mac_type { txgbe_mac_unknown = 0, txgbe_mac_raptor, @@ -177,6 +184,15 @@ struct txgbe_rom_info { s32 (*validate_checksum)(struct txgbe_hw *hw, u16 *checksum_val); s32 (*update_checksum)(struct txgbe_hw *hw); s32 (*calc_checksum)(struct txgbe_hw *hw); + + enum txgbe_eeprom_type type; + u32 semaphore_delay; + u16 word_size; + u16 address_bits; + u16 word_page_size; + u16 ctrl_word_3; + + u32 sw_addr; }; struct txgbe_flash_info { @@ -357,6 +373,11 @@ struct txgbe_hw { uint64_t isb_dma; void IOMEM *isb_mem; + enum txgbe_reset_type { + TXGBE_LAN_RESET = 0, + TXGBE_SW_RESET, + TXGBE_GLOBAL_RESET + } reset_type; }; #include "txgbe_regs.h" diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c index 85970a0366..7bafe4123a 100644 --- a/drivers/net/txgbe/txgbe_ethdev.c +++ b/drivers/net/txgbe/txgbe_ethdev.c @@ -51,6 +51,7 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) struct txgbe_hw *hw = TXGBE_DEV_HW(eth_dev); struct rte_intr_handle *intr_handle = &pci_dev->intr_handle; const struct rte_memzone *mz; + uint16_t csum; int err; PMD_INIT_FUNC_TRACE(); @@ -81,6 +82,19 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) return -EIO; } + err = hw->rom.init_params(hw); + if (err != 0) { + PMD_INIT_LOG(ERR, "The EEPROM init failed: %d", err); + return -EIO; + } + + /* Make sure we have a good EEPROM before we read from it */ + err = hw->rom.validate_checksum(hw, &csum); + if (err != 0) { + PMD_INIT_LOG(ERR, "The EEPROM checksum is not valid: %d", err); + return -EIO; + } + /* Allocate memory for storing MAC addresses */ eth_dev->data->mac_addrs = rte_zmalloc("txgbe", RTE_ETHER_ADDR_LEN * hw->mac.num_rar_entries, 0);