Move EEPROM information query from a sysctl in mlx5en(4) to an ioctl
in mlx5core. The EEPROM information is not only a property of the mlx5en(4) driver. Submitted by: slavash@ MFC after: 3 days Sponsored by: Mellanox Technologies
This commit is contained in:
parent
6deb0b1e94
commit
048ddb58bc
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=352983
@ -25,18 +25,18 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd May 7, 2019
|
||||
.Dd October 2, 2019
|
||||
.Dt mlx5io 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm mlx5io
|
||||
.Nd IOCTL interface to manage Connect-X 4/5 Mellanox network adapters
|
||||
.Nd IOCTL interface to manage Connect-X 4/5/6 Mellanox network adapters
|
||||
.Sh SYNOPSIS
|
||||
.In dev/mlx5/mlx5io.h
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
interface is provided for management of the Connect-X 4 and 5 network adapters
|
||||
interface is provided for management of the Connect-X4, 5 and 6 network adapters
|
||||
in the aspects not covered by the generic network configuration,
|
||||
mostly related to the PCIe attachment and internal card working.
|
||||
Interface consists of the commands, which are passed by means of
|
||||
@ -147,6 +147,29 @@ Requests PCIe link-level reset on the device.
|
||||
The address of the device is specified by the
|
||||
.Vt struct mlx5_tool_addr
|
||||
structure, which should be passed as an argument.
|
||||
.It Dv MLX5_EEPROM_GET
|
||||
Fetch EEPROM information.
|
||||
The argument to the command should point to the input/output
|
||||
.Vt struct mlx5_eeprom_get
|
||||
structure where, the
|
||||
.Dv devaddr
|
||||
field specifies the address of the device.
|
||||
.Bd -literal
|
||||
struct mlx5_eeprom_get {
|
||||
struct mlx5_tool_addr devaddr;
|
||||
size_t eeprom_info_page_valid;
|
||||
uint32_t *eeprom_info_buf;
|
||||
size_t eeprom_info_out_len;
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
On successfull return, the
|
||||
.Dv eeprom_info_out_len
|
||||
field reports the length of the EEPROM information.
|
||||
.Dv eeprom_info_buf
|
||||
field contains the actual EEPROM information.
|
||||
.Dv eeprom_info_page_valid
|
||||
field reports the third page validity.
|
||||
.El
|
||||
.Sh FILES
|
||||
The
|
||||
|
@ -32,6 +32,8 @@
|
||||
#define MLX5_CORE_DIAGNOSTICS_STRUCT(n, s, t) s,
|
||||
#define MLX5_CORE_DIAGNOSTICS_ENTRY(n, s, t) { #s, (t) },
|
||||
|
||||
static MALLOC_DEFINE(M_MLX5_EEPROM, "MLX5EEPROM", "MLX5 EEPROM information");
|
||||
|
||||
struct mlx5_core_diagnostics_entry {
|
||||
const char *desc;
|
||||
u16 counter_id;
|
||||
@ -127,6 +129,18 @@ union mlx5_core_general_diagnostics {
|
||||
extern const struct mlx5_core_diagnostics_entry
|
||||
mlx5_core_general_diagnostics_table[MLX5_CORE_GENERAL_DIAGNOSTICS_NUM];
|
||||
|
||||
struct mlx5_eeprom {
|
||||
int lock_bit;
|
||||
int i2c_addr;
|
||||
int page_num;
|
||||
int device_addr;
|
||||
int module_num;
|
||||
int len;
|
||||
int type;
|
||||
int page_valid;
|
||||
u32 *data;
|
||||
};
|
||||
|
||||
/* function prototypes */
|
||||
int mlx5_core_set_diagnostics_full(struct mlx5_core_dev *mdev,
|
||||
u8 enable_pci, u8 enable_general);
|
||||
@ -134,5 +148,8 @@ int mlx5_core_get_diagnostics_full(struct mlx5_core_dev *mdev,
|
||||
union mlx5_core_pci_diagnostics *ppci,
|
||||
union mlx5_core_general_diagnostics *pgen);
|
||||
int mlx5_core_supports_diagnostics(struct mlx5_core_dev *mdev, u16 counter_id);
|
||||
int mlx5_read_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom);
|
||||
int mlx5_get_eeprom_info(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom);
|
||||
int mlx5_get_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *ee);
|
||||
|
||||
#endif /* MLX5_CORE_DIAGNOSTICS_H */
|
||||
|
@ -26,7 +26,10 @@
|
||||
*/
|
||||
|
||||
#include <dev/mlx5/driver.h>
|
||||
#include <dev/mlx5/port.h>
|
||||
#include <dev/mlx5/diagnostics.h>
|
||||
#include <dev/mlx5/mlx5_core/mlx5_core.h>
|
||||
#include <net/sff8472.h>
|
||||
|
||||
const struct mlx5_core_diagnostics_entry
|
||||
mlx5_core_pci_diagnostics_table[
|
||||
@ -284,3 +287,156 @@ int mlx5_core_supports_diagnostics(struct mlx5_core_dev *dev, u16 counter_id)
|
||||
}
|
||||
return 0; /* not supported counter */
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the first three bytes of the eeprom in order to get the needed info
|
||||
* for the whole reading.
|
||||
* Byte 0 - Identifier byte
|
||||
* Byte 1 - Revision byte
|
||||
* Byte 2 - Status byte
|
||||
*/
|
||||
int
|
||||
mlx5_get_eeprom_info(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom)
|
||||
{
|
||||
u32 data = 0;
|
||||
int size_read = 0;
|
||||
int ret;
|
||||
|
||||
ret = mlx5_query_module_num(dev, &eeprom->module_num);
|
||||
if (ret) {
|
||||
mlx5_core_err(dev, "Failed query module error=%d\n", ret);
|
||||
return (-ret);
|
||||
}
|
||||
|
||||
/* Read the first three bytes to get Identifier, Revision and Status */
|
||||
ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
|
||||
eeprom->device_addr, MLX5_EEPROM_INFO_BYTES, eeprom->module_num, &data,
|
||||
&size_read);
|
||||
if (ret) {
|
||||
mlx5_core_err(dev,
|
||||
"Failed query EEPROM module error=0x%x\n", ret);
|
||||
return (-ret);
|
||||
}
|
||||
|
||||
switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
|
||||
case SFF_8024_ID_QSFP:
|
||||
eeprom->type = MLX5_ETH_MODULE_SFF_8436;
|
||||
eeprom->len = MLX5_ETH_MODULE_SFF_8436_LEN;
|
||||
break;
|
||||
case SFF_8024_ID_QSFPPLUS:
|
||||
case SFF_8024_ID_QSFP28:
|
||||
if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
|
||||
((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
|
||||
eeprom->type = MLX5_ETH_MODULE_SFF_8636;
|
||||
eeprom->len = MLX5_ETH_MODULE_SFF_8636_LEN;
|
||||
} else {
|
||||
eeprom->type = MLX5_ETH_MODULE_SFF_8436;
|
||||
eeprom->len = MLX5_ETH_MODULE_SFF_8436_LEN;
|
||||
}
|
||||
if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
|
||||
eeprom->page_valid = 1;
|
||||
break;
|
||||
case SFF_8024_ID_SFP:
|
||||
eeprom->type = MLX5_ETH_MODULE_SFF_8472;
|
||||
eeprom->len = MLX5_ETH_MODULE_SFF_8472_LEN;
|
||||
break;
|
||||
default:
|
||||
mlx5_core_err(dev, "Not recognized cable type = 0x%x(%s)\n",
|
||||
data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
|
||||
sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
|
||||
return (EINVAL);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read both low and high pages of the eeprom */
|
||||
int
|
||||
mlx5_get_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *ee)
|
||||
{
|
||||
int size_read = 0;
|
||||
int ret;
|
||||
|
||||
if (ee->len == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* Read low page of the eeprom */
|
||||
while (ee->device_addr < ee->len) {
|
||||
ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
|
||||
ee->len - ee->device_addr, ee->module_num,
|
||||
ee->data + (ee->device_addr / 4), &size_read);
|
||||
if (ret) {
|
||||
mlx5_core_err(dev,
|
||||
"Failed reading EEPROM, error = 0x%02x\n", ret);
|
||||
return (-ret);
|
||||
}
|
||||
ee->device_addr += size_read;
|
||||
}
|
||||
|
||||
/* Read high page of the eeprom */
|
||||
if (ee->page_valid == 1) {
|
||||
ee->device_addr = MLX5_EEPROM_HIGH_PAGE_OFFSET;
|
||||
ee->page_num = MLX5_EEPROM_HIGH_PAGE;
|
||||
size_read = 0;
|
||||
while (ee->device_addr < MLX5_EEPROM_PAGE_LENGTH) {
|
||||
ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
|
||||
ee->device_addr, MLX5_EEPROM_PAGE_LENGTH - ee->device_addr,
|
||||
ee->module_num, ee->data + (ee->len / 4) +
|
||||
((ee->device_addr - MLX5_EEPROM_HIGH_PAGE_OFFSET) / 4),
|
||||
&size_read);
|
||||
if (ret) {
|
||||
mlx5_core_err(dev,
|
||||
"Failed reading EEPROM, error = 0x%02x\n",
|
||||
ret);
|
||||
return (-ret);
|
||||
}
|
||||
ee->device_addr += size_read;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read cable EEPROM module information by first inspecting the first
|
||||
* three bytes to get the initial information for a whole reading.
|
||||
* Information will be printed to dmesg.
|
||||
*/
|
||||
int
|
||||
mlx5_read_eeprom(struct mlx5_core_dev *dev, struct mlx5_eeprom *eeprom)
|
||||
{
|
||||
int error;
|
||||
|
||||
eeprom->i2c_addr = MLX5_I2C_ADDR_LOW;
|
||||
eeprom->device_addr = 0;
|
||||
eeprom->page_num = MLX5_EEPROM_LOW_PAGE;
|
||||
eeprom->page_valid = 0;
|
||||
|
||||
/* Read three first bytes to get important info */
|
||||
error = mlx5_get_eeprom_info(dev, eeprom);
|
||||
if (error) {
|
||||
mlx5_core_err(dev,
|
||||
"Failed reading EEPROM initial information\n");
|
||||
return (error);
|
||||
}
|
||||
/*
|
||||
* Allocate needed length buffer and additional space for
|
||||
* page 0x03
|
||||
*/
|
||||
eeprom->data = malloc(eeprom->len + MLX5_EEPROM_PAGE_LENGTH,
|
||||
M_MLX5_EEPROM, M_WAITOK | M_ZERO);
|
||||
|
||||
/* Read the whole eeprom information */
|
||||
error = mlx5_get_eeprom(dev, eeprom);
|
||||
if (error) {
|
||||
mlx5_core_err(dev, "Failed reading EEPROM\n");
|
||||
error = 0;
|
||||
/*
|
||||
* Continue printing partial information in case of
|
||||
* an error
|
||||
*/
|
||||
}
|
||||
free(eeprom->data, M_MLX5_EEPROM);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,8 +32,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/fcntl.h>
|
||||
#include <dev/mlx5/driver.h>
|
||||
#include <dev/mlx5/device.h>
|
||||
#include <dev/mlx5/port.h>
|
||||
#include <dev/mlx5/mlx5_core/mlx5_core.h>
|
||||
#include <dev/mlx5/mlx5io.h>
|
||||
#include <dev/mlx5/diagnostics.h>
|
||||
|
||||
static MALLOC_DEFINE(M_MLX5_DUMP, "MLX5DUMP", "MLX5 Firmware dump");
|
||||
|
||||
@ -305,6 +307,54 @@ mlx5_fw_reset(struct mlx5_core_dev *mdev)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5_eeprom_copyout(struct mlx5_core_dev *dev, struct mlx5_eeprom_get *eeprom_info)
|
||||
{
|
||||
struct mlx5_eeprom eeprom;
|
||||
int error;
|
||||
|
||||
eeprom.i2c_addr = MLX5_I2C_ADDR_LOW;
|
||||
eeprom.device_addr = 0;
|
||||
eeprom.page_num = MLX5_EEPROM_LOW_PAGE;
|
||||
eeprom.page_valid = 0;
|
||||
|
||||
/* Read three first bytes to get important info */
|
||||
error = mlx5_get_eeprom_info(dev, &eeprom);
|
||||
if (error != 0) {
|
||||
mlx5_core_err(dev,
|
||||
"Failed reading EEPROM initial information\n");
|
||||
return (error);
|
||||
}
|
||||
eeprom_info->eeprom_info_page_valid = eeprom.page_valid;
|
||||
eeprom_info->eeprom_info_out_len = eeprom.len;
|
||||
|
||||
if (eeprom_info->eeprom_info_buf == NULL)
|
||||
return (0);
|
||||
/*
|
||||
* Allocate needed length buffer and additional space for
|
||||
* page 0x03
|
||||
*/
|
||||
eeprom.data = malloc(eeprom.len + MLX5_EEPROM_PAGE_LENGTH,
|
||||
M_MLX5_EEPROM, M_WAITOK | M_ZERO);
|
||||
|
||||
/* Read the whole eeprom information */
|
||||
error = mlx5_get_eeprom(dev, &eeprom);
|
||||
if (error != 0) {
|
||||
mlx5_core_err(dev, "Failed reading EEPROM error = %d\n",
|
||||
error);
|
||||
error = 0;
|
||||
/*
|
||||
* Continue printing partial information in case of
|
||||
* an error
|
||||
*/
|
||||
}
|
||||
error = copyout(eeprom.data, eeprom_info->eeprom_info_buf,
|
||||
eeprom.len);
|
||||
free(eeprom.data, M_MLX5_EEPROM);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
mlx5_ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
struct thread *td)
|
||||
@ -314,6 +364,7 @@ mlx5_ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
struct mlx5_tool_addr *devaddr;
|
||||
struct mlx5_fw_update *fu;
|
||||
struct firmware fake_fw;
|
||||
struct mlx5_eeprom_get *eeprom_info;
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
@ -392,6 +443,18 @@ mlx5_ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
break;
|
||||
error = mlx5_fw_reset(mdev);
|
||||
break;
|
||||
case MLX5_EEPROM_GET:
|
||||
if ((fflag & FREAD) == 0) {
|
||||
error = EBADF;
|
||||
break;
|
||||
}
|
||||
eeprom_info = (struct mlx5_eeprom_get *)data;
|
||||
devaddr = &eeprom_info->devaddr;
|
||||
error = mlx5_dbsf_to_core(devaddr, &mdev);
|
||||
if (error != 0)
|
||||
break;
|
||||
error = mlx5_eeprom_copyout(mdev, eeprom_info);
|
||||
break;
|
||||
default:
|
||||
error = ENOTTY;
|
||||
break;
|
||||
|
@ -714,34 +714,6 @@ struct mlx5e_params_ethtool {
|
||||
u8 trust_state;
|
||||
};
|
||||
|
||||
/* EEPROM Standards for plug in modules */
|
||||
#ifndef MLX5E_ETH_MODULE_SFF_8472
|
||||
#define MLX5E_ETH_MODULE_SFF_8472 0x1
|
||||
#define MLX5E_ETH_MODULE_SFF_8472_LEN 128
|
||||
#endif
|
||||
|
||||
#ifndef MLX5E_ETH_MODULE_SFF_8636
|
||||
#define MLX5E_ETH_MODULE_SFF_8636 0x2
|
||||
#define MLX5E_ETH_MODULE_SFF_8636_LEN 256
|
||||
#endif
|
||||
|
||||
#ifndef MLX5E_ETH_MODULE_SFF_8436
|
||||
#define MLX5E_ETH_MODULE_SFF_8436 0x3
|
||||
#define MLX5E_ETH_MODULE_SFF_8436_LEN 256
|
||||
#endif
|
||||
|
||||
/* EEPROM I2C Addresses */
|
||||
#define MLX5E_I2C_ADDR_LOW 0x50
|
||||
#define MLX5E_I2C_ADDR_HIGH 0x51
|
||||
|
||||
#define MLX5E_EEPROM_LOW_PAGE 0x0
|
||||
#define MLX5E_EEPROM_HIGH_PAGE 0x3
|
||||
|
||||
#define MLX5E_EEPROM_HIGH_PAGE_OFFSET 128
|
||||
#define MLX5E_EEPROM_PAGE_LENGTH 256
|
||||
|
||||
#define MLX5E_EEPROM_INFO_BYTES 0x3
|
||||
|
||||
struct mlx5e_cq {
|
||||
/* data path - accessed per cqe */
|
||||
struct mlx5_cqwq wq;
|
||||
|
@ -901,214 +901,6 @@ mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the first three bytes of the eeprom in order to get the needed info
|
||||
* for the whole reading.
|
||||
* Byte 0 - Identifier byte
|
||||
* Byte 1 - Revision byte
|
||||
* Byte 2 - Status byte
|
||||
*/
|
||||
static int
|
||||
mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
|
||||
{
|
||||
struct mlx5_core_dev *dev = priv->mdev;
|
||||
u32 data = 0;
|
||||
int size_read = 0;
|
||||
int ret;
|
||||
|
||||
ret = mlx5_query_module_num(dev, &eeprom->module_num);
|
||||
if (ret) {
|
||||
mlx5_en_err(priv->ifp, "Failed query module error=%d\n",
|
||||
ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Read the first three bytes to get Identifier, Revision and Status */
|
||||
ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
|
||||
eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
|
||||
&size_read);
|
||||
if (ret) {
|
||||
mlx5_en_err(priv->ifp,
|
||||
"Failed query eeprom module error=0x%x\n", ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
|
||||
case SFF_8024_ID_QSFP:
|
||||
eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
|
||||
eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
|
||||
break;
|
||||
case SFF_8024_ID_QSFPPLUS:
|
||||
case SFF_8024_ID_QSFP28:
|
||||
if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
|
||||
((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
|
||||
eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
|
||||
eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
|
||||
} else {
|
||||
eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
|
||||
eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
|
||||
}
|
||||
if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
|
||||
eeprom->page_valid = 1;
|
||||
break;
|
||||
case SFF_8024_ID_SFP:
|
||||
eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
|
||||
eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
|
||||
break;
|
||||
default:
|
||||
mlx5_en_err(priv->ifp,
|
||||
"Not recognized cable type = 0x%x(%s)\n",
|
||||
data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
|
||||
sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
|
||||
return (EINVAL);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Read both low and high pages of the eeprom */
|
||||
static int
|
||||
mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
|
||||
{
|
||||
struct mlx5_core_dev *dev = priv->mdev;
|
||||
int size_read = 0;
|
||||
int ret;
|
||||
|
||||
if (ee->len == 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* Read low page of the eeprom */
|
||||
while (ee->device_addr < ee->len) {
|
||||
ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
|
||||
ee->len - ee->device_addr, ee->module_num,
|
||||
ee->data + (ee->device_addr / 4), &size_read);
|
||||
if (ret) {
|
||||
mlx5_en_err(priv->ifp,
|
||||
"Failed reading eeprom, error = 0x%02x\n",ret);
|
||||
return (ret);
|
||||
}
|
||||
ee->device_addr += size_read;
|
||||
}
|
||||
|
||||
/* Read high page of the eeprom */
|
||||
if (ee->page_valid) {
|
||||
ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
|
||||
ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
|
||||
size_read = 0;
|
||||
while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
|
||||
ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
|
||||
ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
|
||||
ee->module_num, ee->data + (ee->len / 4) +
|
||||
((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
|
||||
&size_read);
|
||||
if (ret) {
|
||||
mlx5_en_err(priv->ifp,
|
||||
"Failed reading eeprom, error = 0x%02x\n",
|
||||
ret);
|
||||
return (ret);
|
||||
}
|
||||
ee->device_addr += size_read;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
|
||||
{
|
||||
int row;
|
||||
int index_in_row;
|
||||
int byte_to_write = 0;
|
||||
int line_length = 16;
|
||||
|
||||
printf("\nOffset\t\tValues\n");
|
||||
printf("------\t\t------");
|
||||
while (byte_to_write < eeprom->len) {
|
||||
printf("\n0x%04X\t\t", byte_to_write);
|
||||
for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
|
||||
printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
|
||||
byte_to_write++;
|
||||
}
|
||||
}
|
||||
|
||||
if (eeprom->page_valid) {
|
||||
row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
|
||||
printf("\n\nUpper Page 0x03\n");
|
||||
printf("\nOffset\t\tValues\n");
|
||||
printf("------\t\t------");
|
||||
while (row < MLX5E_EEPROM_PAGE_LENGTH) {
|
||||
printf("\n0x%04X\t\t", row);
|
||||
for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
|
||||
printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
|
||||
byte_to_write++;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read cable EEPROM module information by first inspecting the first
|
||||
* three bytes to get the initial information for a whole reading.
|
||||
* Information will be printed to dmesg.
|
||||
*/
|
||||
static int
|
||||
mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct mlx5e_priv *priv = arg1;
|
||||
struct mlx5e_eeprom eeprom;
|
||||
int error;
|
||||
int result = 0;
|
||||
|
||||
PRIV_LOCK(priv);
|
||||
error = sysctl_handle_int(oidp, &result, 0, req);
|
||||
if (error || !req->newptr)
|
||||
goto done;
|
||||
|
||||
/* Check if device is gone */
|
||||
if (priv->gone) {
|
||||
error = ENXIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (result == 1) {
|
||||
eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
|
||||
eeprom.device_addr = 0;
|
||||
eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
|
||||
eeprom.page_valid = 0;
|
||||
|
||||
/* Read three first bytes to get important info */
|
||||
error = mlx5e_get_eeprom_info(priv, &eeprom);
|
||||
if (error) {
|
||||
mlx5_en_err(priv->ifp,
|
||||
"Failed reading eeprom's initial information\n");
|
||||
error = 0;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* Allocate needed length buffer and additional space for
|
||||
* page 0x03
|
||||
*/
|
||||
eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
|
||||
M_MLX5EN, M_WAITOK | M_ZERO);
|
||||
|
||||
/* Read the whole eeprom information */
|
||||
error = mlx5e_get_eeprom(priv, &eeprom);
|
||||
if (error) {
|
||||
mlx5_en_err(priv->ifp, "Failed reading eeprom\n");
|
||||
error = 0;
|
||||
/*
|
||||
* Continue printing partial information in case of
|
||||
* an error
|
||||
*/
|
||||
}
|
||||
mlx5e_print_eeprom(&eeprom);
|
||||
free(eeprom.data, M_MLX5EN);
|
||||
}
|
||||
done:
|
||||
PRIV_UNLOCK(priv);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static const char *mlx5e_params_desc[] = {
|
||||
MLX5E_PARAMS(MLX5E_STATS_DESC)
|
||||
};
|
||||
@ -1347,11 +1139,6 @@ mlx5e_create_ethtool(struct mlx5e_priv *priv)
|
||||
__DECONST(void *, pnameunit), 0,
|
||||
"PCI device name");
|
||||
|
||||
/* EEPROM support */
|
||||
SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
|
||||
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
|
||||
mlx5e_read_eeprom, "I", "EEPROM information");
|
||||
|
||||
/* Diagnostics support */
|
||||
mlx5e_create_diagnostics(priv);
|
||||
|
||||
|
@ -3397,9 +3397,9 @@ mlx5e_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
* The internal conversion is as follows:
|
||||
*/
|
||||
if (i2c.dev_addr == 0xA0)
|
||||
read_addr = MLX5E_I2C_ADDR_LOW;
|
||||
read_addr = MLX5_I2C_ADDR_LOW;
|
||||
else if (i2c.dev_addr == 0xA2)
|
||||
read_addr = MLX5E_I2C_ADDR_HIGH;
|
||||
read_addr = MLX5_I2C_ADDR_HIGH;
|
||||
else {
|
||||
mlx5_en_err(ifp,
|
||||
"Query eeprom failed, Invalid Address: %X\n",
|
||||
@ -3408,7 +3408,7 @@ mlx5e_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
goto err_i2c;
|
||||
}
|
||||
error = mlx5_query_eeprom(priv->mdev,
|
||||
read_addr, MLX5E_EEPROM_LOW_PAGE,
|
||||
read_addr, MLX5_EEPROM_LOW_PAGE,
|
||||
(uint32_t)i2c.offset, (uint32_t)i2c.len, module_num,
|
||||
(uint32_t *)i2c.data, &size_read);
|
||||
if (error) {
|
||||
@ -3420,7 +3420,7 @@ mlx5e_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
|
||||
if (i2c.len > MLX5_EEPROM_MAX_BYTES) {
|
||||
error = mlx5_query_eeprom(priv->mdev,
|
||||
read_addr, MLX5E_EEPROM_LOW_PAGE,
|
||||
read_addr, MLX5_EEPROM_LOW_PAGE,
|
||||
(uint32_t)(i2c.offset + size_read),
|
||||
(uint32_t)(i2c.len - size_read), module_num,
|
||||
(uint32_t *)(i2c.data + size_read), &size_read);
|
||||
|
@ -55,11 +55,19 @@ struct mlx5_fw_update {
|
||||
size_t img_fw_data_len;
|
||||
};
|
||||
|
||||
struct mlx5_eeprom_get {
|
||||
struct mlx5_tool_addr devaddr;
|
||||
uint32_t *eeprom_info_buf;
|
||||
uint8_t eeprom_info_page_valid;
|
||||
size_t eeprom_info_out_len;
|
||||
};
|
||||
|
||||
#define MLX5_FWDUMP_GET _IOWR('m', 1, struct mlx5_fwdump_get)
|
||||
#define MLX5_FWDUMP_RESET _IOW('m', 2, struct mlx5_tool_addr)
|
||||
#define MLX5_FWDUMP_FORCE _IOW('m', 3, struct mlx5_tool_addr)
|
||||
#define MLX5_FW_UPDATE _IOW('m', 4, struct mlx5_fw_update)
|
||||
#define MLX5_FW_RESET _IOW('m', 5, struct mlx5_tool_addr)
|
||||
#define MLX5_EEPROM_GET _IOWR('m', 6, struct mlx5_eeprom_get)
|
||||
|
||||
#ifndef _KERNEL
|
||||
#define MLX5_DEV_PATH _PATH_DEV"mlx5ctl"
|
||||
|
@ -50,13 +50,34 @@ enum mlx5_an_status {
|
||||
MLX5_AN_LINK_DOWN = 4,
|
||||
};
|
||||
|
||||
/* EEPROM I2C Addresses */
|
||||
#define MLX5_I2C_ADDR_LOW 0x50
|
||||
#define MLX5_I2C_ADDR_HIGH 0x51
|
||||
#define MLX5_EEPROM_PAGE_LENGTH 256
|
||||
#define MLX5_EEPROM_MAX_BYTES 32
|
||||
#define MLX5_EEPROM_IDENTIFIER_BYTE_MASK 0x000000ff
|
||||
#define MLX5_EEPROM_REVISION_ID_BYTE_MASK 0x0000ff00
|
||||
#define MLX5_EEPROM_PAGE_3_VALID_BIT_MASK 0x00040000
|
||||
#define MLX5_I2C_ADDR_LOW 0x50
|
||||
#define MLX5_I2C_ADDR_HIGH 0x51
|
||||
#define MLX5_EEPROM_PAGE_LENGTH 256
|
||||
#define MLX5_EEPROM_LOW_PAGE 0x0
|
||||
#define MLX5_EEPROM_HIGH_PAGE 0x3
|
||||
#define MLX5_EEPROM_HIGH_PAGE_OFFSET 128
|
||||
#define MLX5_EEPROM_INFO_BYTES 0x3
|
||||
|
||||
/* EEPROM Standards for plug in modules */
|
||||
#ifndef MLX5_ETH_MODULE_SFF_8472
|
||||
#define MLX5_ETH_MODULE_SFF_8472 0x1
|
||||
#define MLX5_ETH_MODULE_SFF_8472_LEN 128
|
||||
#endif
|
||||
|
||||
#ifndef MLX5_ETH_MODULE_SFF_8636
|
||||
#define MLX5_ETH_MODULE_SFF_8636 0x2
|
||||
#define MLX5_ETH_MODULE_SFF_8636_LEN 256
|
||||
#endif
|
||||
|
||||
#ifndef MLX5_ETH_MODULE_SFF_8436
|
||||
#define MLX5_ETH_MODULE_SFF_8436 0x3
|
||||
#define MLX5_ETH_MODULE_SFF_8436_LEN 256
|
||||
#endif
|
||||
|
||||
enum mlx5e_link_speed {
|
||||
MLX5E_1000BASE_CX_SGMII = 0,
|
||||
|
Loading…
Reference in New Issue
Block a user