[dpdk-stable] [PATCH 18.11 04/10] net/atlantic: eeprom get/set should consider offset

Igor Russkikh Igor.Russkikh at aquantia.com
Sat May 18 11:47:41 CEST 2019


From: Pavel Belous <pavel.belous at aquantia.com>

EEPROM get/set offset logic should take offset into account.
Data transfers to/from FW should also correctly use
dword based transfer interface, taking into account the
remainder.
We also check error code returned from FW.

cc: stable at dpdk.org
Fixes: ce4e8d418097 ("net/atlantic: implement EEPROM get/set")
Signed-off-by: Igor Russkikh <igor.russkikh at aquantia.com>
Signed-off-by: Pavel Belous <pavel.belous at aquantia.com>
Signed-off-by: Pavel Belous <Pavel.Belous at aquantia.com>
---
 drivers/net/atlantic/atl_ethdev.c             |  20 +++-
 drivers/net/atlantic/atl_types.h              |   6 +-
 drivers/net/atlantic/hw_atl/hw_atl_utils.h    |  16 +--
 .../net/atlantic/hw_atl/hw_atl_utils_fw2x.c   | 109 +++++++++++++-----
 4 files changed, 104 insertions(+), 47 deletions(-)

diff --git a/drivers/net/atlantic/atl_ethdev.c b/drivers/net/atlantic/atl_ethdev.c
index 5bc04f55cc21..6b289702d849 100644
--- a/drivers/net/atlantic/atl_ethdev.c
+++ b/drivers/net/atlantic/atl_ethdev.c
@@ -1106,28 +1106,40 @@ static int
 atl_dev_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom)
 {
 	struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int dev_addr = SMBUS_DEVICE_ID;
 
 	if (hw->aq_fw_ops->get_eeprom == NULL)
 		return -ENOTSUP;
 
-	if (eeprom->length != SFP_EEPROM_SIZE || eeprom->data == NULL)
+	if (eeprom->length + eeprom->offset > SFP_EEPROM_SIZE ||
+	    eeprom->data == NULL)
 		return -EINVAL;
 
-	return hw->aq_fw_ops->get_eeprom(hw, eeprom->data, eeprom->length);
+	if (eeprom->magic)
+		dev_addr = eeprom->magic;
+
+	return hw->aq_fw_ops->get_eeprom(hw, dev_addr, eeprom->data,
+					 eeprom->length, eeprom->offset);
 }
 
 static int
 atl_dev_set_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom)
 {
 	struct aq_hw_s *hw = ATL_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int dev_addr = SMBUS_DEVICE_ID;
 
 	if (hw->aq_fw_ops->set_eeprom == NULL)
 		return -ENOTSUP;
 
-	if (eeprom->length != SFP_EEPROM_SIZE || eeprom->data == NULL)
+	if (eeprom->length + eeprom->offset > SFP_EEPROM_SIZE ||
+	    eeprom->data == NULL)
 		return -EINVAL;
 
-	return hw->aq_fw_ops->set_eeprom(hw, eeprom->data, eeprom->length);
+	if (eeprom->magic)
+		dev_addr = eeprom->magic;
+
+	return hw->aq_fw_ops->set_eeprom(hw, dev_addr, eeprom->data,
+					 eeprom->length, eeprom->offset);
 }
 
 static int
diff --git a/drivers/net/atlantic/atl_types.h b/drivers/net/atlantic/atl_types.h
index 3d90f6caefc2..96622745d495 100644
--- a/drivers/net/atlantic/atl_types.h
+++ b/drivers/net/atlantic/atl_types.h
@@ -137,9 +137,11 @@ struct aq_fw_ops {
 
 	int (*led_control)(struct aq_hw_s *self, u32 mode);
 
-	int (*get_eeprom)(struct aq_hw_s *self, u32 *data, u32 len);
+	int (*get_eeprom)(struct aq_hw_s *self, int dev_addr,
+			u32 *data, u32 len, u32 offset);
 
-	int (*set_eeprom)(struct aq_hw_s *self, u32 *data, u32 len);
+	int (*set_eeprom)(struct aq_hw_s *self, int dev_addr,
+			u32 *data, u32 len, u32 offset);
 };
 
 struct atl_sw_stats {
diff --git a/drivers/net/atlantic/hw_atl/hw_atl_utils.h b/drivers/net/atlantic/hw_atl/hw_atl_utils.h
index 5f3f70847310..b1f03f42e8b8 100644
--- a/drivers/net/atlantic/hw_atl/hw_atl_utils.h
+++ b/drivers/net/atlantic/hw_atl/hw_atl_utils.h
@@ -336,15 +336,8 @@ struct offload_info {
 	u8 buf[0];
 } __attribute__((__packed__));
 
-struct smbus_read_request {
-	u32 offset; /* not used */
-	u32 device_id;
-	u32 address;
-	u32 length;
-} __attribute__((__packed__));
-
-struct smbus_write_request {
-	u32 offset; /* not used */
+struct smbus_request {
+	u32 msg_id; /* not used */
 	u32 device_id;
 	u32 address;
 	u32 length;
@@ -389,8 +382,6 @@ enum hal_atl_utils_fw_state_e {
 #define HAL_ATLANTIC_UTILS_FW_MSG_OFFLOAD_DEL  10U
 #define HAL_ATLANTIC_UTILS_FW_MSG_CABLE_DIAG   13U // 0xd
 
-#define SMBUS_READ_REQUEST BIT(13)
-#define SMBUS_WRITE_REQUEST BIT(14)
 #define SMBUS_DEVICE_ID 0x50
 
 enum hw_atl_fw2x_rate {
@@ -414,6 +405,9 @@ enum hw_atl_fw2x_caps_lo {
 	CAPS_LO_2P5GBASET_FD,
 	CAPS_LO_5GBASET_FD,
 	CAPS_LO_10GBASET_FD,
+	CAPS_LO_AUTONEG,
+	CAPS_LO_SMBUS_READ,
+	CAPS_LO_SMBUS_WRITE,
 };
 
 enum hw_atl_fw2x_caps_hi {
diff --git a/drivers/net/atlantic/hw_atl/hw_atl_utils_fw2x.c b/drivers/net/atlantic/hw_atl/hw_atl_utils_fw2x.c
index 6841d9bce39c..e0fb850c9aac 100644
--- a/drivers/net/atlantic/hw_atl/hw_atl_utils_fw2x.c
+++ b/drivers/net/atlantic/hw_atl/hw_atl_utils_fw2x.c
@@ -484,38 +484,42 @@ static int aq_fw2x_led_control(struct aq_hw_s *self, u32 mode)
 	return 0;
 }
 
-static int aq_fw2x_get_eeprom(struct aq_hw_s *self, u32 *data, u32 len)
+static int aq_fw2x_get_eeprom(struct aq_hw_s *self, int dev_addr,
+			u32 *data, u32 len, u32 offset)
 {
-	int err = 0;
-	struct smbus_read_request request;
-	u32 mpi_opts;
+	u32 bytes_remains = len % sizeof(u32);
+	u32 num_dwords = len / sizeof(u32);
+	struct smbus_request request;
 	u32 result = 0;
+	u32 mpi_opts;
+	int err = 0;
 
 	if (self->fw_ver_actual < HW_ATL_FW_FEATURE_EEPROM)
 		return -EOPNOTSUPP;
 
-	request.device_id = SMBUS_DEVICE_ID;
-	request.address = 0;
+	request.msg_id = 0;
+	request.device_id = dev_addr;
+	request.address = offset;
 	request.length = len;
 
 	/* Write SMBUS request to cfg memory */
 	err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
 				(u32 *)(void *)&request,
-				RTE_ALIGN(sizeof(request), sizeof(u32)));
+				sizeof(request) / sizeof(u32));
 
 	if (err < 0)
 		return err;
 
-	/* Toggle 0x368.SMBUS_READ_REQUEST bit */
+	/* Toggle 0x368.CAPS_LO_SMBUS_READ bit */
 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
-	mpi_opts ^= SMBUS_READ_REQUEST;
+	mpi_opts ^= BIT(CAPS_LO_SMBUS_READ);
 
 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
 
 	/* Wait until REQUEST_BIT matched in 0x370 */
 
 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
-		SMBUS_READ_REQUEST) == (mpi_opts & SMBUS_READ_REQUEST),
+		BIT(CAPS_LO_SMBUS_READ)) == (mpi_opts & BIT(CAPS_LO_SMBUS_READ)),
 		10U, 10000U);
 
 	if (err < 0)
@@ -523,64 +527,106 @@ static int aq_fw2x_get_eeprom(struct aq_hw_s *self, u32 *data, u32 len)
 
 	err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
 			&result,
-			RTE_ALIGN(sizeof(result), sizeof(u32)));
+			sizeof(result) / sizeof(u32));
 
 	if (err < 0)
 		return err;
 
-	if (result == 0) {
+	if (result)
+		return -EIO;
+
+	if (num_dwords) {
+		err = hw_atl_utils_fw_downld_dwords(self,
+			self->rpc_addr + sizeof(u32) * 2,
+			data,
+			num_dwords);
+
+		if (err < 0)
+			return err;
+	}
+
+	if (bytes_remains) {
+		u32 val = 0;
+
 		err = hw_atl_utils_fw_downld_dwords(self,
-				self->rpc_addr + sizeof(u32) * 2,
-				data,
-				RTE_ALIGN(len, sizeof(u32)));
+			self->rpc_addr + (sizeof(u32) * 2) +
+			(num_dwords * sizeof(u32)),
+			&val,
+			1);
 
 		if (err < 0)
 			return err;
+
+		rte_memcpy((u8 *)data + len - bytes_remains,
+			&val, bytes_remains);
 	}
 
 	return 0;
 }
 
 
-static int aq_fw2x_set_eeprom(struct aq_hw_s *self, u32 *data, u32 len)
+static int aq_fw2x_set_eeprom(struct aq_hw_s *self, int dev_addr,
+				u32 *data, u32 len, u32 offset)
 {
-	struct smbus_write_request request;
+	struct smbus_request request;
 	u32 mpi_opts, result = 0;
 	int err = 0;
 
 	if (self->fw_ver_actual < HW_ATL_FW_FEATURE_EEPROM)
 		return -EOPNOTSUPP;
 
-	request.device_id = SMBUS_DEVICE_ID;
-	request.address = 0;
+	request.msg_id = 0;
+	request.device_id = dev_addr;
+	request.address = offset;
 	request.length = len;
 
 	/* Write SMBUS request to cfg memory */
 	err = hw_atl_utils_fw_upload_dwords(self, self->rpc_addr,
 				(u32 *)(void *)&request,
-				RTE_ALIGN(sizeof(request), sizeof(u32)));
+				sizeof(request) / sizeof(u32));
 
 	if (err < 0)
 		return err;
 
 	/* Write SMBUS data to cfg memory */
-	err = hw_atl_utils_fw_upload_dwords(self,
-				self->rpc_addr + sizeof(request),
-				(u32 *)(void *)data,
-				RTE_ALIGN(len, sizeof(u32)));
+	u32 num_dwords = len / sizeof(u32);
+	u32 bytes_remains = len % sizeof(u32);
 
-	if (err < 0)
-		return err;
+	if (num_dwords) {
+		err = hw_atl_utils_fw_upload_dwords(self,
+			self->rpc_addr + sizeof(request),
+			(u32 *)(void *)data,
+			num_dwords);
+
+		if (err < 0)
+			return err;
+	}
+
+	if (bytes_remains) {
+		u32 val = 0;
+
+		rte_memcpy(&val, (u8 *)data + (sizeof(u32) * num_dwords),
+			bytes_remains);
 
-	/* Toggle 0x368.SMBUS_WRITE_REQUEST bit */
+		err = hw_atl_utils_fw_upload_dwords(self,
+			self->rpc_addr + sizeof(request) +
+			(num_dwords * sizeof(u32)),
+			&val,
+			1);
+
+		if (err < 0)
+			return err;
+	}
+
+	/* Toggle 0x368.CAPS_LO_SMBUS_WRITE bit */
 	mpi_opts = aq_hw_read_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR);
-	mpi_opts ^= SMBUS_WRITE_REQUEST;
+	mpi_opts ^= BIT(CAPS_LO_SMBUS_WRITE);
 
 	aq_hw_write_reg(self, HW_ATL_FW2X_MPI_CONTROL_ADDR, mpi_opts);
 
 	/* Wait until REQUEST_BIT matched in 0x370 */
 	AQ_HW_WAIT_FOR((aq_hw_read_reg(self, HW_ATL_FW2X_MPI_STATE_ADDR) &
-		SMBUS_WRITE_REQUEST) == (mpi_opts & SMBUS_WRITE_REQUEST),
+		BIT(CAPS_LO_SMBUS_WRITE)) == (mpi_opts & BIT(CAPS_LO_SMBUS_WRITE)),
 		10U, 10000U);
 
 	if (err < 0)
@@ -589,11 +635,14 @@ static int aq_fw2x_set_eeprom(struct aq_hw_s *self, u32 *data, u32 len)
 	/* Read status of write operation */
 	err = hw_atl_utils_fw_downld_dwords(self, self->rpc_addr + sizeof(u32),
 				&result,
-				RTE_ALIGN(sizeof(result), sizeof(u32)));
+				sizeof(result) / sizeof(u32));
 
 	if (err < 0)
 		return err;
 
+	if (result)
+		return -EIO;
+
 	return 0;
 }
 
-- 
2.17.1



More information about the stable mailing list