From patchwork Thu Jun 17 10:59:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 94331 X-Patchwork-Delegate: andrew.rybchenko@oktetlabs.ru Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id ED08EA0C4D; Thu, 17 Jun 2021 12:58:54 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 4F6D441121; Thu, 17 Jun 2021 12:58:22 +0200 (CEST) Received: from smtpbg506.qq.com (smtpbg506.qq.com [203.205.250.33]) by mails.dpdk.org (Postfix) with ESMTP id B0651410FC for ; Thu, 17 Jun 2021 12:58:19 +0200 (CEST) X-QQ-mid: bizesmtp46t1623927495tpdjpa6h Received: from wxdbg.localdomain.com (unknown [183.129.236.74]) by esmtp6.qq.com (ESMTP) with id ; Thu, 17 Jun 2021 18:58:14 +0800 (CST) X-QQ-SSF: 01400000000000D0E000B00A0000000 X-QQ-FEAT: ChTsRoALjQDaJpQ4lAf0tM2Y8EguggKeq/vHfipXaceItB0qLXxCL7B01rvuK tYAbxvtWXyGAzfT0gpF1fvbydbq555kBiqyrTH5fjOcT0gC8pgftzAljpXU/Z/tAYJC/02M zXyYoOsF3AXozV3uzktX7MHX+LtTpPA09BpCZPRf7QQz3a79daosgZweNl4DBJAM5gtAD0H e44CGAp/fOp16z3VsIB4Tkr3YW9Z0xa0rg8+snWs7IX8BCYTQ1n/D7JleERqo2/ihzntzjL V/UmKyRC4f2bKnDyBnQ442NFttB9CZ0bwPcfSBxJ28KQmdXGtHTYSwl2pcb6NvX2gC4SYnb U4Tgl041uzCWs1Yan/lOyt+yFheTlbTAG/ZDcBW X-QQ-GoodBg: 2 From: Jiawen Wu To: dev@dpdk.org Cc: Jiawen Wu Date: Thu, 17 Jun 2021 18:59:52 +0800 Message-Id: <20210617110005.4132926-7-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20210617110005.4132926-1-jiawenwu@trustnetic.com> References: <20210617110005.4132926-1-jiawenwu@trustnetic.com> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybgforeign:qybgforeign5 X-QQ-Bgrelay: 1 Subject: [dpdk-dev] [PATCH v6 06/19] net/ngbe: init and validate EEPROM X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Reset swfw lock before NVM access, init EEPROM and validate the checksum. Signed-off-by: Jiawen Wu --- drivers/net/ngbe/base/meson.build | 2 + drivers/net/ngbe/base/ngbe_dummy.h | 23 ++++ drivers/net/ngbe/base/ngbe_eeprom.c | 203 ++++++++++++++++++++++++++++ drivers/net/ngbe/base/ngbe_eeprom.h | 17 +++ drivers/net/ngbe/base/ngbe_hw.c | 83 ++++++++++++ drivers/net/ngbe/base/ngbe_hw.h | 3 + drivers/net/ngbe/base/ngbe_mng.c | 198 +++++++++++++++++++++++++++ drivers/net/ngbe/base/ngbe_mng.h | 65 +++++++++ drivers/net/ngbe/base/ngbe_type.h | 24 ++++ drivers/net/ngbe/ngbe_ethdev.c | 39 ++++++ 10 files changed, 657 insertions(+) create mode 100644 drivers/net/ngbe/base/ngbe_eeprom.c create mode 100644 drivers/net/ngbe/base/ngbe_eeprom.h create mode 100644 drivers/net/ngbe/base/ngbe_mng.c create mode 100644 drivers/net/ngbe/base/ngbe_mng.h diff --git a/drivers/net/ngbe/base/meson.build b/drivers/net/ngbe/base/meson.build index fdbfa99916..ddd122ec45 100644 --- a/drivers/net/ngbe/base/meson.build +++ b/drivers/net/ngbe/base/meson.build @@ -2,7 +2,9 @@ # Copyright(c) 2018-2020 Beijing WangXun Technology Co., Ltd. sources = [ + 'ngbe_eeprom.c', 'ngbe_hw.c', + 'ngbe_mng.c', ] error_cflags = [] diff --git a/drivers/net/ngbe/base/ngbe_dummy.h b/drivers/net/ngbe/base/ngbe_dummy.h index 75b4e50bca..ade03eae81 100644 --- a/drivers/net/ngbe/base/ngbe_dummy.h +++ b/drivers/net/ngbe/base/ngbe_dummy.h @@ -28,9 +28,32 @@ static inline void ngbe_bus_set_lan_id_dummy(struct ngbe_hw *TUP0) { } +/* struct ngbe_rom_operations */ +static inline s32 ngbe_rom_init_params_dummy(struct ngbe_hw *TUP0) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline s32 ngbe_rom_validate_checksum_dummy(struct ngbe_hw *TUP0, + u16 *TUP1) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline s32 ngbe_mac_acquire_swfw_sync_dummy(struct ngbe_hw *TUP0, + u32 TUP1) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline void ngbe_mac_release_swfw_sync_dummy(struct ngbe_hw *TUP0, + u32 TUP1) +{ +} static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw) { hw->bus.set_lan_id = ngbe_bus_set_lan_id_dummy; + hw->rom.init_params = ngbe_rom_init_params_dummy; + hw->rom.validate_checksum = ngbe_rom_validate_checksum_dummy; + hw->mac.acquire_swfw_sync = ngbe_mac_acquire_swfw_sync_dummy; + hw->mac.release_swfw_sync = ngbe_mac_release_swfw_sync_dummy; } #endif /* _NGBE_TYPE_DUMMY_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_eeprom.c b/drivers/net/ngbe/base/ngbe_eeprom.c new file mode 100644 index 0000000000..0ebbb7a29e --- /dev/null +++ b/drivers/net/ngbe/base/ngbe_eeprom.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2020 Beijing WangXun Technology Co., Ltd. + * Copyright(c) 2010-2017 Intel Corporation + */ + +#include "ngbe_hw.h" +#include "ngbe_mng.h" +#include "ngbe_eeprom.h" + +/** + * ngbe_init_eeprom_params - Initialize EEPROM params + * @hw: pointer to hardware structure + * + * Initializes the EEPROM parameters ngbe_rom_info within the + * ngbe_hw struct in order to set up EEPROM access. + **/ +s32 ngbe_init_eeprom_params(struct ngbe_hw *hw) +{ + struct ngbe_rom_info *eeprom = &hw->rom; + u32 eec; + u16 eeprom_size; + + DEBUGFUNC("ngbe_init_eeprom_params"); + + if (eeprom->type != ngbe_eeprom_unknown) + return 0; + + eeprom->type = ngbe_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, NGBE_SPISTAT); + if (!(eec & NGBE_SPISTAT_BPFLASH)) { + eeprom->type = ngbe_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; + eeprom->sw_addr = 0x80; + + 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; +} + +/** + * ngbe_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 ngbe_get_eeprom_semaphore(struct ngbe_hw *hw) +{ + s32 status = NGBE_ERR_EEPROM; + u32 timeout = 2000; + u32 i; + u32 swsm; + + DEBUGFUNC("ngbe_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, NGBE_SWSEM); + if (!(swsm & NGBE_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 + */ + ngbe_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, NGBE_SWSEM); + if (!(swsm & NGBE_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, NGBE_MNGSWSYNC, + NGBE_MNGSWSYNC_REQ, NGBE_MNGSWSYNC_REQ); + + /* + * If we set the bit successfully then we got the + * semaphore. + */ + swsm = rd32(hw, NGBE_MNGSWSYNC); + if (swsm & NGBE_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"); + ngbe_release_eeprom_semaphore(hw); + status = NGBE_ERR_EEPROM; + } + } else { + DEBUGOUT("Software semaphore SMBI between device drivers " + "not granted.\n"); + } + + return status; +} + +/** + * ngbe_release_eeprom_semaphore - Release hardware semaphore + * @hw: pointer to hardware structure + * + * This function clears hardware semaphore bits. + **/ +void ngbe_release_eeprom_semaphore(struct ngbe_hw *hw) +{ + DEBUGFUNC("ngbe_release_eeprom_semaphore"); + + wr32m(hw, NGBE_MNGSWSYNC, NGBE_MNGSWSYNC_REQ, 0); + wr32m(hw, NGBE_SWSEM, NGBE_SWSEM_PF, 0); + ngbe_flush(hw); +} + +/** + * ngbe_validate_eeprom_checksum_em - 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 ngbe_validate_eeprom_checksum_em(struct ngbe_hw *hw, + u16 *checksum_val) +{ + u32 eeprom_cksum_devcap = 0; + int err = 0; + + DEBUGFUNC("ngbe_validate_eeprom_checksum_em"); + UNREFERENCED_PARAMETER(checksum_val); + + /* Check EEPROM only once */ + if (hw->bus.lan_id == 0) { + wr32(hw, NGBE_CALSUM_CAP_STATUS, 0x0); + wr32(hw, NGBE_EEPROM_VERSION_STORE_REG, 0x0); + } else { + eeprom_cksum_devcap = rd32(hw, NGBE_CALSUM_CAP_STATUS); + hw->rom.saved_version = rd32(hw, NGBE_EEPROM_VERSION_STORE_REG); + } + + if (hw->bus.lan_id == 0 || eeprom_cksum_devcap == 0) { + err = ngbe_hic_check_cap(hw); + if (err != 0) { + PMD_INIT_LOG(ERR, + "The EEPROM checksum is not valid: %d", err); + return -EIO; + } + } + + hw->rom.cksum_devcap = eeprom_cksum_devcap & 0xffff; + + return err; +} + diff --git a/drivers/net/ngbe/base/ngbe_eeprom.h b/drivers/net/ngbe/base/ngbe_eeprom.h new file mode 100644 index 0000000000..0c2819df4a --- /dev/null +++ b/drivers/net/ngbe/base/ngbe_eeprom.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2020 Beijing WangXun Technology Co., Ltd. + * Copyright(c) 2010-2017 Intel Corporation + */ + +#ifndef _NGBE_EEPROM_H_ +#define _NGBE_EEPROM_H_ + +#define NGBE_CALSUM_CAP_STATUS 0x10224 +#define NGBE_EEPROM_VERSION_STORE_REG 0x1022C + +s32 ngbe_init_eeprom_params(struct ngbe_hw *hw); +s32 ngbe_validate_eeprom_checksum_em(struct ngbe_hw *hw, u16 *checksum_val); +s32 ngbe_get_eeprom_semaphore(struct ngbe_hw *hw); +void ngbe_release_eeprom_semaphore(struct ngbe_hw *hw); + +#endif /* _NGBE_EEPROM_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_hw.c b/drivers/net/ngbe/base/ngbe_hw.c index 014bb0faee..de6b75e1c0 100644 --- a/drivers/net/ngbe/base/ngbe_hw.c +++ b/drivers/net/ngbe/base/ngbe_hw.c @@ -4,6 +4,8 @@ */ #include "ngbe_type.h" +#include "ngbe_eeprom.h" +#include "ngbe_mng.h" #include "ngbe_hw.h" /** @@ -25,6 +27,77 @@ void ngbe_set_lan_id_multi_port(struct ngbe_hw *hw) bus->func = bus->lan_id; } +/** + * ngbe_acquire_swfw_sync - Acquire SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to acquire + * + * Acquires the SWFW semaphore through the MNGSEM register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +s32 ngbe_acquire_swfw_sync(struct ngbe_hw *hw, u32 mask) +{ + u32 mngsem = 0; + u32 swmask = NGBE_MNGSEM_SW(mask); + u32 fwmask = NGBE_MNGSEM_FW(mask); + u32 timeout = 200; + u32 i; + + DEBUGFUNC("ngbe_acquire_swfw_sync"); + + for (i = 0; i < timeout; i++) { + /* + * SW NVM semaphore bit is used for access to all + * SW_FW_SYNC bits (not just NVM) + */ + if (ngbe_get_eeprom_semaphore(hw)) + return NGBE_ERR_SWFW_SYNC; + + mngsem = rd32(hw, NGBE_MNGSEM); + if (mngsem & (fwmask | swmask)) { + /* Resource is currently in use by FW or SW */ + ngbe_release_eeprom_semaphore(hw); + msec_delay(5); + } else { + mngsem |= swmask; + wr32(hw, NGBE_MNGSEM, mngsem); + ngbe_release_eeprom_semaphore(hw); + return 0; + } + } + + /* If time expired clear the bits holding the lock and retry */ + if (mngsem & (fwmask | swmask)) + ngbe_release_swfw_sync(hw, mngsem & (fwmask | swmask)); + + msec_delay(5); + return NGBE_ERR_SWFW_SYNC; +} + +/** + * ngbe_release_swfw_sync - Release SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to release + * + * Releases the SWFW semaphore through the MNGSEM register for the specified + * function (CSR, PHY0, PHY1, EEPROM, Flash) + **/ +void ngbe_release_swfw_sync(struct ngbe_hw *hw, u32 mask) +{ + u32 mngsem; + u32 swmask = mask; + + DEBUGFUNC("ngbe_release_swfw_sync"); + + ngbe_get_eeprom_semaphore(hw); + + mngsem = rd32(hw, NGBE_MNGSEM); + mngsem &= ~swmask; + wr32(hw, NGBE_MNGSEM, mngsem); + + ngbe_release_eeprom_semaphore(hw); +} + /** * ngbe_set_mac_type - Sets MAC type * @hw: pointer to the HW structure @@ -134,12 +207,22 @@ void ngbe_map_device_id(struct ngbe_hw *hw) s32 ngbe_init_ops_pf(struct ngbe_hw *hw) { struct ngbe_bus_info *bus = &hw->bus; + struct ngbe_mac_info *mac = &hw->mac; + struct ngbe_rom_info *rom = &hw->rom; DEBUGFUNC("ngbe_init_ops_pf"); /* BUS */ bus->set_lan_id = ngbe_set_lan_id_multi_port; + /* MAC */ + mac->acquire_swfw_sync = ngbe_acquire_swfw_sync; + mac->release_swfw_sync = ngbe_release_swfw_sync; + + /* EEPROM */ + rom->init_params = ngbe_init_eeprom_params; + rom->validate_checksum = ngbe_validate_eeprom_checksum_em; + return 0; } diff --git a/drivers/net/ngbe/base/ngbe_hw.h b/drivers/net/ngbe/base/ngbe_hw.h index 7d5de49248..5e508fb67f 100644 --- a/drivers/net/ngbe/base/ngbe_hw.h +++ b/drivers/net/ngbe/base/ngbe_hw.h @@ -10,6 +10,9 @@ void ngbe_set_lan_id_multi_port(struct ngbe_hw *hw); +s32 ngbe_acquire_swfw_sync(struct ngbe_hw *hw, u32 mask); +void ngbe_release_swfw_sync(struct ngbe_hw *hw, u32 mask); + s32 ngbe_init_shared_code(struct ngbe_hw *hw); s32 ngbe_set_mac_type(struct ngbe_hw *hw); s32 ngbe_init_ops_pf(struct ngbe_hw *hw); diff --git a/drivers/net/ngbe/base/ngbe_mng.c b/drivers/net/ngbe/base/ngbe_mng.c new file mode 100644 index 0000000000..87891a91e1 --- /dev/null +++ b/drivers/net/ngbe/base/ngbe_mng.c @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2020 Beijing WangXun Technology Co., Ltd. + * Copyright(c) 2010-2017 Intel Corporation + */ + +#include "ngbe_type.h" +#include "ngbe_mng.h" + +/** + * ngbe_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 NGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + * + * This function assumes that the NGBE_MNGSEM_SWMBX semaphore is held + * by the caller. + **/ +static s32 +ngbe_hic_unlocked(struct ngbe_hw *hw, u32 *buffer, u32 length, u32 timeout) +{ + u32 value, loop; + u16 i, dword_len; + + DEBUGFUNC("ngbe_hic_unlocked"); + + if (!length || length > NGBE_PMMBX_BSIZE) { + DEBUGOUT("Buffer length failure buffersize=%d.\n", length); + return NGBE_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 NGBE_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, NGBE_MNGMBX, i, cpu_to_le32(buffer[i])); + buffer[i] = rd32a(hw, NGBE_MNGMBX, i); + } + ngbe_flush(hw); + + /* Setting this bit tells the ARC that a new command is pending. */ + wr32m(hw, NGBE_MNGMBXCTL, + NGBE_MNGMBXCTL_SWRDY, NGBE_MNGMBXCTL_SWRDY); + + /* Check command completion */ + loop = po32m(hw, NGBE_MNGMBXCTL, + NGBE_MNGMBXCTL_FWRDY, NGBE_MNGMBXCTL_FWRDY, + &value, timeout, 1000); + if (!loop || !(value & NGBE_MNGMBXCTL_FWACK)) { + DEBUGOUT("Command has failed with no status valid.\n"); + return NGBE_ERR_HOST_INTERFACE_COMMAND; + } + + return 0; +} + +/** + * ngbe_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 NGBE_ERR_HOST_INTERFACE_COMMAND when command fails. + **/ +static s32 +ngbe_host_interface_command(struct ngbe_hw *hw, u32 *buffer, + u32 length, u32 timeout, bool return_data) +{ + u32 hdr_size = sizeof(struct ngbe_hic_hdr); + struct ngbe_hic_hdr *resp = (struct ngbe_hic_hdr *)buffer; + u16 buf_len; + s32 err; + u32 bi; + u32 dword_len; + + DEBUGFUNC("ngbe_host_interface_command"); + + if (length == 0 || length > NGBE_PMMBX_BSIZE) { + DEBUGOUT("Buffer length failure buffersize=%d.\n", length); + return NGBE_ERR_HOST_INTERFACE_COMMAND; + } + + /* Take management host interface semaphore */ + err = hw->mac.acquire_swfw_sync(hw, NGBE_MNGSEM_SWMBX); + if (err) + return err; + + err = ngbe_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, NGBE_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, NGBE_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 = NGBE_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, NGBE_MNGMBX, bi); + +rel_out: + hw->mac.release_swfw_sync(hw, NGBE_MNGSEM_SWMBX); + + return err; +} + +s32 ngbe_hic_check_cap(struct ngbe_hw *hw) +{ + struct ngbe_hic_read_shadow_ram command; + s32 err; + int i; + + DEBUGFUNC("\n"); + + command.hdr.req.cmd = FW_EEPROM_CHECK_STATUS; + command.hdr.req.buf_lenh = 0; + command.hdr.req.buf_lenl = 0; + command.hdr.req.checksum = FW_DEFAULT_CHECKSUM; + + /* convert offset from words to bytes */ + command.address = 0; + /* one word */ + command.length = 0; + + for (i = 0; i <= FW_CEM_MAX_RETRIES; i++) { + err = ngbe_host_interface_command(hw, (u32 *)&command, + sizeof(command), + NGBE_HI_COMMAND_TIMEOUT, true); + if (err) + continue; + + command.hdr.rsp.ret_status &= 0x1F; + if (command.hdr.rsp.ret_status != + FW_CEM_RESP_STATUS_SUCCESS) + err = NGBE_ERR_HOST_INTERFACE_COMMAND; + + break; + } + + if (!err && command.address != FW_CHECKSUM_CAP_ST_PASS) + err = NGBE_ERR_EEPROM_CHECKSUM; + + return err; +} diff --git a/drivers/net/ngbe/base/ngbe_mng.h b/drivers/net/ngbe/base/ngbe_mng.h new file mode 100644 index 0000000000..383e0dc0d1 --- /dev/null +++ b/drivers/net/ngbe/base/ngbe_mng.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2018-2020 Beijing WangXun Technology Co., Ltd. + * Copyright(c) 2010-2017 Intel Corporation + */ + +#ifndef _NGBE_MNG_H_ +#define _NGBE_MNG_H_ + +#include "ngbe_type.h" + +#define NGBE_PMMBX_QSIZE 64 /* Num of dwords in range */ +#define NGBE_PMMBX_BSIZE (NGBE_PMMBX_QSIZE * 4) +#define NGBE_HI_COMMAND_TIMEOUT 5000 /* Process HI command limit */ + +/* CEM Support */ +#define FW_CEM_MAX_RETRIES 3 +#define FW_CEM_RESP_STATUS_SUCCESS 0x1 +#define FW_DEFAULT_CHECKSUM 0xFF /* checksum always 0xFF */ +#define FW_EEPROM_CHECK_STATUS 0xE9 + +#define FW_CHECKSUM_CAP_ST_PASS 0x80658383 +#define FW_CHECKSUM_CAP_ST_FAIL 0x70657376 + +/* Host Interface Command Structures */ +struct ngbe_hic_hdr { + u8 cmd; + u8 buf_len; + union { + u8 cmd_resv; + u8 ret_status; + } cmd_or_resp; + u8 checksum; +}; + +struct ngbe_hic_hdr2_req { + u8 cmd; + u8 buf_lenh; + u8 buf_lenl; + u8 checksum; +}; + +struct ngbe_hic_hdr2_rsp { + u8 cmd; + u8 buf_lenl; + u8 ret_status; /* 7-5: high bits of buf_len, 4-0: status */ + u8 checksum; +}; + +union ngbe_hic_hdr2 { + struct ngbe_hic_hdr2_req req; + struct ngbe_hic_hdr2_rsp rsp; +}; + +/* These need to be dword aligned */ +struct ngbe_hic_read_shadow_ram { + union ngbe_hic_hdr2 hdr; + u32 address; + u16 length; + u16 pad2; + u16 data; + u16 pad3; +}; + +s32 ngbe_hic_check_cap(struct ngbe_hw *hw); +#endif /* _NGBE_MNG_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_type.h b/drivers/net/ngbe/base/ngbe_type.h index d172f2702f..c727338bd5 100644 --- a/drivers/net/ngbe/base/ngbe_type.h +++ b/drivers/net/ngbe/base/ngbe_type.h @@ -10,6 +10,13 @@ #include "ngbe_osdep.h" #include "ngbe_devids.h" +enum ngbe_eeprom_type { + ngbe_eeprom_unknown = 0, + ngbe_eeprom_spi, + ngbe_eeprom_flash, + ngbe_eeprom_none /* No NVM support */ +}; + enum ngbe_mac_type { ngbe_mac_unknown = 0, ngbe_mac_em, @@ -49,7 +56,23 @@ struct ngbe_bus_info { u8 lan_id; }; +struct ngbe_rom_info { + s32 (*init_params)(struct ngbe_hw *hw); + s32 (*validate_checksum)(struct ngbe_hw *hw, u16 *checksum_val); + + enum ngbe_eeprom_type type; + u32 semaphore_delay; + u16 word_size; + u16 address_bits; + u16 word_page_size; + u32 sw_addr; + u32 saved_version; + u16 cksum_devcap; +}; + struct ngbe_mac_info { + s32 (*acquire_swfw_sync)(struct ngbe_hw *hw, u32 mask); + void (*release_swfw_sync)(struct ngbe_hw *hw, u32 mask); enum ngbe_mac_type type; }; @@ -63,6 +86,7 @@ struct ngbe_hw { void *back; struct ngbe_mac_info mac; struct ngbe_phy_info phy; + struct ngbe_rom_info rom; struct ngbe_bus_info bus; u16 device_id; u16 vendor_id; diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c index a355c7dc29..c779c46dd5 100644 --- a/drivers/net/ngbe/ngbe_ethdev.c +++ b/drivers/net/ngbe/ngbe_ethdev.c @@ -32,6 +32,29 @@ static const struct rte_pci_id pci_id_ngbe_map[] = { { .vendor_id = 0, /* sentinel */ }, }; +/* + * Ensure that all locks are released before first NVM or PHY access + */ +static void +ngbe_swfw_lock_reset(struct ngbe_hw *hw) +{ + uint16_t mask; + + /* + * These ones are more tricky since they are common to all ports; but + * swfw_sync retries last long enough (1s) to be almost sure that if + * lock can not be taken it is due to an improper lock of the + * semaphore. + */ + mask = NGBE_MNGSEM_SWPHY | + NGBE_MNGSEM_SWMBX | + NGBE_MNGSEM_SWFLASH; + if (hw->mac.acquire_swfw_sync(hw, mask) < 0) + PMD_DRV_LOG(DEBUG, "SWFW common locks released"); + + hw->mac.release_swfw_sync(hw, mask); +} + static int eth_ngbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) { @@ -60,6 +83,22 @@ eth_ngbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) return -EIO; } + /* Unlock any pending hardware semaphore */ + ngbe_swfw_lock_reset(hw); + + 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, NULL); + if (err != 0) { + PMD_INIT_LOG(ERR, "The EEPROM checksum is not valid: %d", err); + return -EIO; + } + return 0; }