mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-26 21:54:11 +08:00
qed: Add nvram selftest
Signed-off-by: Yuval Mintz <Yuval.Mintz@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0fefbfbaad
commit
7a4b21b7d1
@ -8666,6 +8666,8 @@ struct public_drv_mb {
|
||||
|
||||
#define DRV_MB_PARAM_BIST_REGISTER_TEST 1
|
||||
#define DRV_MB_PARAM_BIST_CLOCK_TEST 2
|
||||
#define DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES 3
|
||||
#define DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX 4
|
||||
|
||||
#define DRV_MB_PARAM_BIST_RC_UNKNOWN 0
|
||||
#define DRV_MB_PARAM_BIST_RC_PASSED 1
|
||||
@ -8674,6 +8676,8 @@ struct public_drv_mb {
|
||||
|
||||
#define DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT 0
|
||||
#define DRV_MB_PARAM_BIST_TEST_INDEX_MASK 0x000000FF
|
||||
#define DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT 8
|
||||
#define DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_MASK 0x0000FF00
|
||||
|
||||
u32 fw_mb_header;
|
||||
#define FW_MSG_CODE_MASK 0xffff0000
|
||||
|
@ -1508,6 +1508,7 @@ static struct qed_selftest_ops qed_selftest_ops_pass = {
|
||||
.selftest_interrupt = &qed_selftest_interrupt,
|
||||
.selftest_register = &qed_selftest_register,
|
||||
.selftest_clock = &qed_selftest_clock,
|
||||
.selftest_nvram = &qed_selftest_nvram,
|
||||
};
|
||||
|
||||
const struct qed_common_ops qed_common_ops_pass = {
|
||||
|
@ -1434,6 +1434,52 @@ int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len)
|
||||
{
|
||||
u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0;
|
||||
struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
|
||||
u32 resp = 0, resp_param = 0;
|
||||
struct qed_ptt *p_ptt;
|
||||
int rc = 0;
|
||||
|
||||
p_ptt = qed_ptt_acquire(p_hwfn);
|
||||
if (!p_ptt)
|
||||
return -EBUSY;
|
||||
|
||||
while (bytes_left > 0) {
|
||||
bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN);
|
||||
|
||||
rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt,
|
||||
DRV_MSG_CODE_NVM_READ_NVRAM,
|
||||
addr + offset +
|
||||
(bytes_to_copy <<
|
||||
DRV_MB_PARAM_NVM_LEN_SHIFT),
|
||||
&resp, &resp_param,
|
||||
&read_len,
|
||||
(u32 *)(p_buf + offset));
|
||||
|
||||
if (rc || (resp != FW_MSG_CODE_NVM_OK)) {
|
||||
DP_NOTICE(cdev, "MCP command rc = %d\n", rc);
|
||||
break;
|
||||
}
|
||||
|
||||
/* This can be a lengthy process, and it's possible scheduler
|
||||
* isn't preemptable. Sleep a bit to prevent CPU hogging.
|
||||
*/
|
||||
if (bytes_left % 0x1000 <
|
||||
(bytes_left - read_len) % 0x1000)
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
offset += read_len;
|
||||
bytes_left -= read_len;
|
||||
}
|
||||
|
||||
cdev->mcp_nvm_resp = resp;
|
||||
qed_ptt_release(p_hwfn, p_ptt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
|
||||
{
|
||||
u32 drv_mb_param = 0, rsp, param;
|
||||
@ -1475,3 +1521,51 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt,
|
||||
u32 *num_images)
|
||||
{
|
||||
u32 drv_mb_param = 0, rsp;
|
||||
int rc = 0;
|
||||
|
||||
drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES <<
|
||||
DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT);
|
||||
|
||||
rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST,
|
||||
drv_mb_param, &rsp, num_images);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK))
|
||||
rc = -EINVAL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt,
|
||||
struct bist_nvm_image_att *p_image_att,
|
||||
u32 image_index)
|
||||
{
|
||||
u32 buf_size = 0, param, resp = 0, resp_param = 0;
|
||||
int rc;
|
||||
|
||||
param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX <<
|
||||
DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT;
|
||||
param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT;
|
||||
|
||||
rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt,
|
||||
DRV_MSG_CODE_BIST_TEST, param,
|
||||
&resp, &resp_param,
|
||||
&buf_size,
|
||||
(u32 *)p_image_att);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) ||
|
||||
(p_image_att->return_code != 1))
|
||||
rc = -EINVAL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -379,6 +379,18 @@ int qed_mcp_set_led(struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt,
|
||||
enum qed_led_mode mode);
|
||||
|
||||
/**
|
||||
* @brief Read from nvm
|
||||
*
|
||||
* @param cdev
|
||||
* @param addr - nvm offset
|
||||
* @param p_buf - nvm read buffer
|
||||
* @param len - buffer len
|
||||
*
|
||||
* @return int - 0 - operation was successful.
|
||||
*/
|
||||
int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len);
|
||||
|
||||
/**
|
||||
* @brief Bist register test
|
||||
*
|
||||
@ -401,6 +413,35 @@ int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn,
|
||||
int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt);
|
||||
|
||||
/**
|
||||
* @brief Bist nvm test - get number of images
|
||||
*
|
||||
* @param p_hwfn - hw function
|
||||
* @param p_ptt - PTT required for register access
|
||||
* @param num_images - number of images if operation was
|
||||
* successful. 0 if not.
|
||||
*
|
||||
* @return int - 0 - operation was successful.
|
||||
*/
|
||||
int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt,
|
||||
u32 *num_images);
|
||||
|
||||
/**
|
||||
* @brief Bist nvm test - get image attributes by index
|
||||
*
|
||||
* @param p_hwfn - hw function
|
||||
* @param p_ptt - PTT required for register access
|
||||
* @param p_image_att - Attributes of image
|
||||
* @param image_index - Index of image to get information for
|
||||
*
|
||||
* @return int - 0 - operation was successful.
|
||||
*/
|
||||
int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn,
|
||||
struct qed_ptt *p_ptt,
|
||||
struct bist_nvm_image_att *p_image_att,
|
||||
u32 image_index);
|
||||
|
||||
/* Using hwfn number (and not pf_num) is required since in CMT mode,
|
||||
* same pf_num may be used by two different hwfn
|
||||
* TODO - this shouldn't really be in .h file, but until all fields
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <linux/crc32.h>
|
||||
#include "qed.h"
|
||||
#include "qed_dev_api.h"
|
||||
#include "qed_mcp.h"
|
||||
@ -75,3 +76,103 @@ int qed_selftest_clock(struct qed_dev *cdev)
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int qed_selftest_nvram(struct qed_dev *cdev)
|
||||
{
|
||||
struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
|
||||
struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
|
||||
u32 num_images, i, j, nvm_crc, calc_crc;
|
||||
struct bist_nvm_image_att image_att;
|
||||
u8 *buf = NULL;
|
||||
__be32 val;
|
||||
int rc;
|
||||
|
||||
if (!p_ptt) {
|
||||
DP_ERR(p_hwfn, "failed to acquire ptt\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Acquire from MFW the amount of available images */
|
||||
rc = qed_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images);
|
||||
if (rc || !num_images) {
|
||||
DP_ERR(p_hwfn, "Failed getting number of images\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Iterate over images and validate CRC */
|
||||
for (i = 0; i < num_images; i++) {
|
||||
/* This mailbox returns information about the image required for
|
||||
* reading it.
|
||||
*/
|
||||
rc = qed_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt,
|
||||
&image_att, i);
|
||||
if (rc) {
|
||||
DP_ERR(p_hwfn,
|
||||
"Failed getting image index %d attributes\n",
|
||||
i);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* After MFW crash dump is collected - the image's CRC stops
|
||||
* being valid.
|
||||
*/
|
||||
if (image_att.image_type == NVM_TYPE_MDUMP)
|
||||
continue;
|
||||
|
||||
DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n",
|
||||
i, image_att.len);
|
||||
|
||||
/* Allocate a buffer for holding the nvram image */
|
||||
buf = kzalloc(image_att.len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
rc = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* Read image into buffer */
|
||||
rc = qed_mcp_nvm_read(p_hwfn->cdev, image_att.nvm_start_addr,
|
||||
buf, image_att.len);
|
||||
if (rc) {
|
||||
DP_ERR(p_hwfn,
|
||||
"Failed reading image index %d from nvm.\n", i);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Convert the buffer into big-endian format (excluding the
|
||||
* closing 4 bytes of CRC).
|
||||
*/
|
||||
for (j = 0; j < image_att.len - 4; j += 4) {
|
||||
val = cpu_to_be32(*(u32 *)&buf[j]);
|
||||
*(u32 *)&buf[j] = (__force u32)val;
|
||||
}
|
||||
|
||||
/* Calc CRC for the "actual" image buffer, i.e. not including
|
||||
* the last 4 CRC bytes.
|
||||
*/
|
||||
nvm_crc = *(u32 *)(buf + image_att.len - 4);
|
||||
calc_crc = crc32(0xffffffff, buf, image_att.len - 4);
|
||||
calc_crc = (__force u32)~cpu_to_be32(calc_crc);
|
||||
DP_VERBOSE(p_hwfn, QED_MSG_SP,
|
||||
"nvm crc 0x%x, calc_crc 0x%x\n", nvm_crc, calc_crc);
|
||||
|
||||
if (calc_crc != nvm_crc) {
|
||||
rc = -EINVAL;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
/* Done with this image; Free to prevent double release
|
||||
* on subsequent failure.
|
||||
*/
|
||||
kfree(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
qed_ptt_release(p_hwfn, p_ptt);
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
kfree(buf);
|
||||
err0:
|
||||
qed_ptt_release(p_hwfn, p_ptt);
|
||||
return rc;
|
||||
}
|
||||
|
@ -37,4 +37,14 @@ int qed_selftest_register(struct qed_dev *cdev);
|
||||
* @return int
|
||||
*/
|
||||
int qed_selftest_clock(struct qed_dev *cdev);
|
||||
|
||||
/**
|
||||
* @brief qed_selftest_nvram - Perform nvram test
|
||||
*
|
||||
* @param cdev
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int qed_selftest_nvram(struct qed_dev *cdev);
|
||||
|
||||
#endif
|
||||
|
@ -157,6 +157,7 @@ enum qede_ethtool_tests {
|
||||
QEDE_ETHTOOL_MEMORY_TEST,
|
||||
QEDE_ETHTOOL_REGISTER_TEST,
|
||||
QEDE_ETHTOOL_CLOCK_TEST,
|
||||
QEDE_ETHTOOL_NVRAM_TEST,
|
||||
QEDE_ETHTOOL_TEST_MAX
|
||||
};
|
||||
|
||||
@ -166,6 +167,7 @@ static const char qede_tests_str_arr[QEDE_ETHTOOL_TEST_MAX][ETH_GSTRING_LEN] = {
|
||||
"Memory (online)\t\t",
|
||||
"Register (online)\t",
|
||||
"Clock (online)\t\t",
|
||||
"Nvram (online)\t\t",
|
||||
};
|
||||
|
||||
static void qede_get_strings_stats(struct qede_dev *edev, u8 *buf)
|
||||
@ -1392,6 +1394,11 @@ static void qede_self_test(struct net_device *dev,
|
||||
buf[QEDE_ETHTOOL_CLOCK_TEST] = 1;
|
||||
etest->flags |= ETH_TEST_FL_FAILED;
|
||||
}
|
||||
|
||||
if (edev->ops->common->selftest->selftest_nvram(edev->cdev)) {
|
||||
buf[QEDE_ETHTOOL_NVRAM_TEST] = 1;
|
||||
etest->flags |= ETH_TEST_FL_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
static int qede_set_tunable(struct net_device *dev,
|
||||
|
@ -402,6 +402,15 @@ struct qed_selftest_ops {
|
||||
* @return 0 on success, error otherwise.
|
||||
*/
|
||||
int (*selftest_clock)(struct qed_dev *cdev);
|
||||
|
||||
/**
|
||||
* @brief selftest_nvram - Perform nvram test
|
||||
*
|
||||
* @param cdev
|
||||
*
|
||||
* @return 0 on success, error otherwise.
|
||||
*/
|
||||
int (*selftest_nvram) (struct qed_dev *cdev);
|
||||
};
|
||||
|
||||
struct qed_common_ops {
|
||||
|
Loading…
Reference in New Issue
Block a user