[v2,16/33] net/ena/hal: phc feature modifications

Message ID 20240304122942.3496-17-shaibran@amazon.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series net/ena: v2.9.0 driver release |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Brandes, Shai March 4, 2024, 12:29 p.m. UTC
From: Shai Brandes <shaibran@amazon.com>

1. PHC algorithm is updated to support reading new PHC values.
2. Update default PHC expiration timeout.
3. Fix a theoretical PHC destroy race.
4. Adjust PHC for multiple devices.
5. PHC activation version check point.

Signed-off-by: Shai Brandes <shaibran@amazon.com>
Reviewed-by: Amit Bernstein <amitbern@amazon.com>
---
 drivers/net/ena/hal/ena_com.c                 | 111 ++++++++++++------
 drivers/net/ena/hal/ena_com.h                 |  31 +++--
 drivers/net/ena/hal/ena_defs/ena_admin_defs.h |  45 +++++--
 3 files changed, 135 insertions(+), 52 deletions(-)
  

Patch

diff --git a/drivers/net/ena/hal/ena_com.c b/drivers/net/ena/hal/ena_com.c
index 31c37b0ab3..fb3ad27d0a 100644
--- a/drivers/net/ena/hal/ena_com.c
+++ b/drivers/net/ena/hal/ena_com.c
@@ -41,10 +41,12 @@ 
 #define ENA_MAX_ADMIN_POLL_US 5000
 
 /* PHC definitions */
-#define ENA_PHC_DEFAULT_EXPIRE_TIMEOUT_USEC 20
+#define ENA_PHC_DEFAULT_EXPIRE_TIMEOUT_USEC 10
 #define ENA_PHC_DEFAULT_BLOCK_TIMEOUT_USEC 1000
-#define ENA_PHC_TIMESTAMP_ERROR 0xFFFFFFFFFFFFFFFF
+#define ENA_PHC_MAX_ERROR_BOUND 0xFFFFFFFF
 #define ENA_PHC_REQ_ID_OFFSET 0xDEAD
+#define ENA_PHC_ERROR_FLAGS (ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP | \
+			     ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND)
 
 /*****************************************************************************/
 /*****************************************************************************/
@@ -1778,16 +1780,21 @@  int ena_com_phc_config(struct ena_com_dev *ena_dev)
 	struct ena_admin_set_feat_cmd set_feat_cmd;
 	int ret = 0;
 
-	/* Get device PHC default configuration */
-	ret = ena_com_get_feature(ena_dev, &get_feat_resp, ENA_ADMIN_PHC_CONFIG, 0);
+	/* Get default device PHC configuration */
+	ret = ena_com_get_feature(ena_dev,
+				  &get_feat_resp,
+				  ENA_ADMIN_PHC_CONFIG,
+				  ENA_ADMIN_PHC_FEATURE_VERSION_0);
 	if (unlikely(ret)) {
 		ena_trc_err(ena_dev, "Failed to get PHC feature configuration, error: %d\n", ret);
 		return ret;
 	}
 
-	/* Supporting only readless PHC retrieval */
-	if (get_feat_resp.u.phc.type != ENA_ADMIN_PHC_TYPE_READLESS) {
-		ena_trc_err(ena_dev, "Unsupported PHC type, error: %d\n", ENA_COM_UNSUPPORTED);
+	/* Supporting only PHC V0 (readless mode with error bound) */
+	if (get_feat_resp.u.phc.version != ENA_ADMIN_PHC_FEATURE_VERSION_0) {
+		ena_trc_err(ena_dev, "Unsupported PHC version (0x%X), error: %d\n",
+			    get_feat_resp.u.phc.version,
+			    ENA_COM_UNSUPPORTED);
 		return ENA_COM_UNSUPPORTED;
 	}
 
@@ -1804,11 +1811,11 @@  int ena_com_phc_config(struct ena_com_dev *ena_dev)
 				   get_feat_resp.u.phc.block_timeout_usec :
 				   ENA_PHC_DEFAULT_BLOCK_TIMEOUT_USEC;
 
-	/* Sanity check - expire timeout must not be above skip timeout */
+	/* Sanity check - expire timeout must not exceed block timeout */
 	if (phc->expire_timeout_usec > phc->block_timeout_usec)
 		phc->expire_timeout_usec = phc->block_timeout_usec;
 
-	/* Prepare PHC feature command with PHC output address */
+	/* Prepare PHC config feature command */
 	memset(&set_feat_cmd, 0x0, sizeof(set_feat_cmd));
 	set_feat_cmd.aq_common_descriptor.opcode = ENA_ADMIN_SET_FEATURE;
 	set_feat_cmd.feat_common.feature_id = ENA_ADMIN_PHC_CONFIG;
@@ -1840,13 +1847,16 @@  int ena_com_phc_config(struct ena_com_dev *ena_dev)
 void ena_com_phc_destroy(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_phc_info *phc = &ena_dev->phc;
-
-	phc->active = false;
+	unsigned long flags = 0;
 
 	/* In case PHC is not supported by the device, silently exiting */
 	if (!phc->virt_addr)
 		return;
 
+	ENA_SPINLOCK_LOCK(phc->lock, flags);
+	phc->active = false;
+	ENA_SPINLOCK_UNLOCK(phc->lock, flags);
+
 	ENA_MEM_FREE_COHERENT(ena_dev->dmadev,
 			      sizeof(*phc->virt_addr),
 			      phc->virt_addr,
@@ -1857,15 +1867,14 @@  void ena_com_phc_destroy(struct ena_com_dev *ena_dev)
 	ENA_SPINLOCK_DESTROY(phc->lock);
 }
 
-int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp)
+int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp)
 {
 	volatile struct ena_admin_phc_resp *read_resp = ena_dev->phc.virt_addr;
+	const ena_time_high_res_t zero_system_time = ENA_TIME_INIT_HIGH_RES();
 	struct ena_com_phc_info *phc = &ena_dev->phc;
-	ena_time_high_res_t initial_time = ENA_TIME_INIT_HIGH_RES();
-	static ena_time_high_res_t start_time;
-	unsigned long flags = 0;
 	ena_time_high_res_t expire_time;
 	ena_time_high_res_t block_time;
+	unsigned long flags = 0;
 	int ret = ENA_COM_OK;
 
 	if (!phc->active) {
@@ -1876,9 +1885,10 @@  int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp)
 	ENA_SPINLOCK_LOCK(phc->lock, flags);
 
 	/* Check if PHC is in blocked state */
-	if (unlikely(ENA_TIME_COMPARE_HIGH_RES(start_time, initial_time))) {
+	if (unlikely(ENA_TIME_COMPARE_HIGH_RES(phc->system_time, zero_system_time))) {
 		/* Check if blocking time expired */
-		block_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(start_time, phc->block_timeout_usec);
+		block_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(phc->system_time,
+							     phc->block_timeout_usec);
 		if (!ENA_TIME_EXPIRE_HIGH_RES(block_time)) {
 			/* PHC is still in blocked state, skip PHC request */
 			phc->stats.phc_skp++;
@@ -1886,22 +1896,23 @@  int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp)
 			goto skip;
 		}
 
-		/* PHC is in active state, update statistics according to req_id and timestamp */
+		/* PHC is in active state, update statistics according to req_id and error_flags */
 		if ((READ_ONCE16(read_resp->req_id) != phc->req_id) ||
-				read_resp->timestamp == ENA_PHC_TIMESTAMP_ERROR)
+		    (read_resp->error_flags & ENA_PHC_ERROR_FLAGS)) {
 			/* Device didn't update req_id during blocking time or timestamp is invalid,
 			 * this indicates on a device error
 			 */
 			phc->stats.phc_err++;
-		else
+		} else {
 			/* Device updated req_id during blocking time with valid timestamp */
 			phc->stats.phc_exp++;
+		}
 	}
 
 	/* Setting relative timeouts */
-	start_time = ENA_GET_SYSTEM_TIME_HIGH_RES();
-	block_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(start_time, phc->block_timeout_usec);
-	expire_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(start_time, phc->expire_timeout_usec);
+	phc->system_time = ENA_GET_SYSTEM_TIME_HIGH_RES();
+	block_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(phc->system_time, phc->block_timeout_usec);
+	expire_time = ENA_GET_SYSTEM_TIMEOUT_HIGH_RES(phc->system_time, phc->expire_timeout_usec);
 
 	/* We expect the device to return this req_id once the new PHC timestamp is updated */
 	phc->req_id++;
@@ -1918,35 +1929,45 @@  int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp)
 	while (1) {
 		if (unlikely(ENA_TIME_EXPIRE_HIGH_RES(expire_time))) {
 			/* Gave up waiting for updated req_id, PHC enters into blocked state until
-			 * passing blocking time
+			 * passing blocking time, during this time any get PHC timestamp or
+			 * error bound requests will fail with device busy error
 			 */
+			phc->error_bound = ENA_PHC_MAX_ERROR_BOUND;
 			ret = ENA_COM_DEVICE_BUSY;
 			break;
 		}
 
 		/* Check if req_id was updated by the device */
 		if (READ_ONCE16(read_resp->req_id) != phc->req_id) {
-			/* req_id was not updated by the device, check again on next loop */
+			/* req_id was not updated by the device yet, check again on next loop */
 			continue;
 		}
 
-		/* req_id was updated which indicates that PHC timestamp was updated too */
-		*timestamp = read_resp->timestamp;
-
-		/* PHC timestamp validty check */
-		if (unlikely(*timestamp == ENA_PHC_TIMESTAMP_ERROR)) {
-			/* Retrieved invalid PHC timestamp, PHC enters into blocked state until
-			 * passing blocking time
+		/* req_id was updated by the device which indicates that PHC timestamp, error_bound
+		 * and error_flags are updated too, checking errors before retrieving timestamp and
+		 * error_bound values
+		 */
+		if (unlikely(read_resp->error_flags & ENA_PHC_ERROR_FLAGS)) {
+			/* Retrieved timestamp or error bound errors, PHC enters into blocked state
+			 * until passing blocking time, during this time any get PHC timestamp or
+			 * error bound requests will fail with device busy error
 			 */
+			phc->error_bound = ENA_PHC_MAX_ERROR_BOUND;
 			ret = ENA_COM_DEVICE_BUSY;
 			break;
 		}
 
-		/* Retrieved valid PHC timestamp */
+		/* PHC timestamp value is returned to the caller */
+		*timestamp = read_resp->timestamp;
+
+		/* Error bound value is cached for future retrieval by caller */
+		phc->error_bound = read_resp->error_bound;
+
+		/* Update statistic on valid PHC timestamp retrieval */
 		phc->stats.phc_cnt++;
 
 		/* This indicates PHC state is active */
-		start_time = initial_time;
+		phc->system_time = zero_system_time;
 		break;
 	}
 
@@ -1956,6 +1977,24 @@  int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp)
 	return ret;
 }
 
+int ena_com_phc_get_error_bound(struct ena_com_dev *ena_dev, u32 *error_bound)
+{
+	struct ena_com_phc_info *phc = &ena_dev->phc;
+	u32 local_error_bound = phc->error_bound;
+
+	if (!phc->active) {
+		ena_trc_err(ena_dev, "PHC feature is not active in the device\n");
+		return ENA_COM_UNSUPPORTED;
+	}
+
+	if (local_error_bound == ENA_PHC_MAX_ERROR_BOUND)
+		return ENA_COM_DEVICE_BUSY;
+
+	*error_bound = local_error_bound;
+
+	return ENA_COM_OK;
+}
+
 int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev)
 {
 	struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read;
@@ -2453,9 +2492,9 @@  int ena_com_dev_reset(struct ena_com_dev *ena_dev,
 
 	reset_val |= reset_reason_lsb << ENA_REGS_DEV_CTL_RESET_REASON_SHIFT;
 
-	if (ena_com_get_cap(ena_dev, ENA_ADMIN_EXTENDED_RESET_REASONS)) {
+	if (ena_com_get_cap(ena_dev, ENA_ADMIN_EXTENDED_RESET_REASONS))
 		reset_val |= reset_reason_msb << ENA_REGS_DEV_CTL_RESET_REASON_EXT_SHIFT;
-	} else if (reset_reason_msb) {
+	else if (reset_reason_msb) {
 		/* In case the device does not support intended
 		 * extended reset reason fallback to generic
 		 */
diff --git a/drivers/net/ena/hal/ena_com.h b/drivers/net/ena/hal/ena_com.h
index cd054595d7..c62016cc06 100644
--- a/drivers/net/ena/hal/ena_com.h
+++ b/drivers/net/ena/hal/ena_com.h
@@ -274,6 +274,9 @@  struct ena_com_phc_info {
 	/* PHC shared memory - virtual address */
 	struct ena_admin_phc_resp *virt_addr;
 
+	/* System time of last PHC request */
+	ena_time_high_res_t system_time;
+
 	/* Spin lock to ensure a single outstanding PHC read */
 	ena_spinlock_t lock;
 
@@ -293,17 +296,20 @@  struct ena_com_phc_info {
 	 */
 	u32 block_timeout_usec;
 
+	/* PHC shared memory - physical address */
+	dma_addr_t phys_addr;
+
+	/* PHC shared memory handle */
+	ena_mem_handle_t mem_handle;
+
+	/* Cached error bound per timestamp sample */
+	u32 error_bound;
+
 	/* Request id sent to the device */
 	u16 req_id;
 
 	/* True if PHC is active in the device */
 	bool active;
-
-	/* PHC shared memory - memory handle */
-	ena_mem_handle_t mem_handle;
-
-	/* PHC shared memory - physical address */
-	dma_addr_t phys_addr;
 };
 
 struct ena_rss {
@@ -468,12 +474,19 @@  int ena_com_phc_config(struct ena_com_dev *ena_dev);
  */
 void ena_com_phc_destroy(struct ena_com_dev *ena_dev);
 
-/* ena_com_phc_get - Retrieve PHC timestamp
+/* ena_com_phc_get_timestamp - Retrieve PHC timestamp
+ * @ena_dev: ENA communication layer struct
+ * @timestamp: Retrieved PHC timestamp
+ * @return - 0 on success, negative value on failure
+ */
+int ena_com_phc_get_timestamp(struct ena_com_dev *ena_dev, u64 *timestamp);
+
+/* ena_com_phc_get_error_bound - Retrieve cached PHC error bound
  * @ena_dev: ENA communication layer struct
- * @timestamp: Retrieve PHC timestamp
+ * @error_bound: Cached PHC error bound
  * @return - 0 on success, negative value on failure
  */
-int ena_com_phc_get(struct ena_com_dev *ena_dev, u64 *timestamp);
+int ena_com_phc_get_error_bound(struct ena_com_dev *ena_dev, u32 *error_bound);
 
 /* ena_com_set_mmio_read_mode - Enable/disable the indirect mmio reg read mechanism
  * @ena_dev: ENA communication layer struct
diff --git a/drivers/net/ena/hal/ena_defs/ena_admin_defs.h b/drivers/net/ena/hal/ena_defs/ena_admin_defs.h
index 438e4a1085..ce8a26721e 100644
--- a/drivers/net/ena/hal/ena_defs/ena_admin_defs.h
+++ b/drivers/net/ena/hal/ena_defs/ena_admin_defs.h
@@ -144,8 +144,14 @@  enum ena_admin_get_stats_scope {
 	ENA_ADMIN_ETH_TRAFFIC                       = 1,
 };
 
-enum ena_admin_get_phc_type {
-	ENA_ADMIN_PHC_TYPE_READLESS                 = 0,
+enum ena_admin_phc_feature_version {
+	/* Readless with error_bound */
+	ENA_ADMIN_PHC_FEATURE_VERSION_0             = 0,
+};
+
+enum ena_admin_phc_error_flags {
+	ENA_ADMIN_PHC_ERROR_FLAG_TIMESTAMP   = BIT(0),
+	ENA_ADMIN_PHC_ERROR_FLAG_ERROR_BOUND = BIT(1),
 };
 
 /* ENA SRD configuration for ENI */
@@ -987,7 +993,8 @@  struct ena_admin_host_info {
 	 * 5 : reserved
 	 * 6 : rx_page_reuse
 	 * 7 : tx_ipv6_csum_offload
-	 * 31:8 : reserved
+	 * 8 : phc
+	 * 31:9 : reserved
 	 */
 	uint32_t driver_supported_features;
 };
@@ -1073,10 +1080,10 @@  struct ena_admin_queue_ext_feature_desc {
 };
 
 struct ena_admin_feature_phc_desc {
-	/* PHC type as defined in enum ena_admin_get_phc_type,
-	 * used only for GET command.
+	/* PHC version as defined in enum ena_admin_phc_feature_version,
+	 * used only for GET command as max supported PHC version by the device.
 	 */
-	uint8_t type;
+	uint8_t version;
 
 	/* Reserved - MBZ */
 	uint8_t reserved1[3];
@@ -1272,13 +1279,23 @@  struct ena_admin_ena_mmio_req_read_less_resp {
 };
 
 struct ena_admin_phc_resp {
+	/* Request Id, received from DB register */
 	uint16_t req_id;
 
 	uint8_t reserved1[6];
 
+	/* PHC timestamp (nsec) */
 	uint64_t timestamp;
 
-	uint8_t reserved2[48];
+	uint8_t reserved2[8];
+
+	/* Timestamp error limit (nsec) */
+	uint32_t error_bound;
+
+	/* Bit field of enum ena_admin_phc_error_flags */
+	uint32_t error_flags;
+
+	uint8_t reserved3[32];
 };
 
 /* aq_common_desc */
@@ -1381,6 +1398,8 @@  struct ena_admin_phc_resp {
 #define ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE_MASK              BIT(6)
 #define ENA_ADMIN_HOST_INFO_TX_IPV6_CSUM_OFFLOAD_SHIFT      7
 #define ENA_ADMIN_HOST_INFO_TX_IPV6_CSUM_OFFLOAD_MASK       BIT(7)
+#define ENA_ADMIN_HOST_INFO_PHC_SHIFT                       8
+#define ENA_ADMIN_HOST_INFO_PHC_MASK                        BIT(8)
 
 /* feature_rss_ind_table */
 #define ENA_ADMIN_FEATURE_RSS_IND_TABLE_ONE_ENTRY_UPDATE_MASK BIT(0)
@@ -1879,6 +1898,18 @@  static inline void set_ena_admin_feature_rss_ind_table_one_entry_update(struct e
 	p->flags |= val & ENA_ADMIN_FEATURE_RSS_IND_TABLE_ONE_ENTRY_UPDATE_MASK;
 }
 
+static inline uint32_t get_ena_admin_host_info_phc(const struct ena_admin_host_info *p)
+{
+	return (p->driver_supported_features &
+		ENA_ADMIN_HOST_INFO_PHC_MASK) >> ENA_ADMIN_HOST_INFO_PHC_SHIFT;
+}
+
+static inline void set_ena_admin_host_info_phc(struct ena_admin_host_info *p, uint32_t val)
+{
+	p->driver_supported_features |= (val << ENA_ADMIN_HOST_INFO_PHC_SHIFT) &
+					 ENA_ADMIN_HOST_INFO_PHC_MASK;
+}
+
 static inline uint8_t get_ena_admin_aenq_common_desc_phase(const struct ena_admin_aenq_common_desc *p)
 {
 	return p->flags & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK;