diff mbox series

[v3,for-next,3/3] RDMA/hns: Add timer allocation support for hip08

Message ID 1543050775-98756-4-git-send-email-oulijun@huawei.com (mailing list archive)
State Superseded
Delegated to: Jason Gunthorpe
Headers show
Series Add DCQCN support for hip08 | expand

Commit Message

Lijun Ou Nov. 24, 2018, 9:12 a.m. UTC
From: Yangyang Li <liyangyang20@huawei.com>

This patch adds qpc timer and cqc timer allocation
support for hardware timeout retransmission in
kernel space driver.

Signed-off-by: Yangyang Li <liyangyang20@huawei.com>
---
 drivers/infiniband/hw/hns/hns_roce_cmd.h    |   8 +++
 drivers/infiniband/hw/hns/hns_roce_device.h |  28 ++++++++
 drivers/infiniband/hw/hns/hns_roce_hem.c    |  42 ++++++++++++
 drivers/infiniband/hw/hns/hns_roce_hem.h    |   2 +
 drivers/infiniband/hw/hns/hns_roce_hw_v2.c  | 103 +++++++++++++++++++++++++++-
 drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |  24 +++++++
 drivers/infiniband/hw/hns/hns_roce_main.c   |  36 ++++++++++
 7 files changed, 242 insertions(+), 1 deletion(-)

Comments

Jason Gunthorpe Dec. 4, 2018, 6:35 p.m. UTC | #1
On Sat, Nov 24, 2018 at 05:12:55PM +0800, Lijun Ou wrote:
> From: Yangyang Li <liyangyang20@huawei.com>
> 
> This patch adds qpc timer and cqc timer allocation
> support for hardware timeout retransmission in
> kernel space driver.
> 
> Signed-off-by: Yangyang Li <liyangyang20@huawei.com>
>  drivers/infiniband/hw/hns/hns_roce_cmd.h    |   8 +++
>  drivers/infiniband/hw/hns/hns_roce_device.h |  28 ++++++++
>  drivers/infiniband/hw/hns/hns_roce_hem.c    |  42 ++++++++++++
>  drivers/infiniband/hw/hns/hns_roce_hem.h    |   2 +
>  drivers/infiniband/hw/hns/hns_roce_hw_v2.c  | 103 +++++++++++++++++++++++++++-
>  drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |  24 +++++++
>  drivers/infiniband/hw/hns/hns_roce_main.c   |  36 ++++++++++
>  7 files changed, 242 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h
> index 5348282..97c5f2c 100644
> +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h
> @@ -93,6 +93,14 @@ enum {
>  	HNS_ROCE_CMD_READ_SCC_CTX_BT0	= 0xa4,
>  	HNS_ROCE_CMD_WRITE_SCC_CTX_BT0	= 0xa5,
>  
> +	/* QPC TIMER commands */
> +	HNS_ROCE_CMD_WRITE_QPC_TIMER_BT0 = 0x33,
> +	HNS_ROCE_CMD_READ_QPC_TIMER_BT0  = 0x37,
> +
> +	/* CQC TIMER commands */
> +	HNS_ROCE_CMD_WRITE_CQC_TIMER_BT0 = 0x23,
> +	HNS_ROCE_CMD_READ_CQC_TIMER_BT0  = 0x27,
> +
>  	/* EQC commands */
>  	HNS_ROCE_CMD_CREATE_AEQC	= 0x80,
>  	HNS_ROCE_CMD_MODIFY_AEQC	= 0x81,
> diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
> index 6fe1871..2a66929 100644
> +++ b/drivers/infiniband/hw/hns/hns_roce_device.h
> @@ -486,6 +486,13 @@ struct hns_roce_qp_table {
>  	struct hns_roce_hem_table	scc_ctx_table;
>  };
>  
> +struct hns_roce_qpc_timer_table {
> +	struct hns_roce_bitmap		bitmap;
> +	spinlock_t			lock;
> +	struct radix_tree_root		tree;

Same comment as for the SRQ patches, lets use xarray instead of adding
new radix_tree users

> +	struct hns_roce_hem_table	table;
> +};
> +
>  struct hns_roce_cq_table {
>  	struct hns_roce_bitmap		bitmap;
>  	spinlock_t			lock;
> @@ -499,6 +506,13 @@ struct hns_roce_srq_table {
>  	struct hns_roce_hem_table	table;
>  };
>  
> +struct hns_roce_cqc_timer_table {
> +	struct hns_roce_bitmap		bitmap;
> +	spinlock_t			lock;
> +	struct radix_tree_root		tree;

Here too

Although, I'm confused, this adds a new struct and a member called
'tree' but the word 'tree' does not appear in this patch otherwise. What is
going on? Where is the user?

Jason
Yangyang Li Dec. 5, 2018, 6:38 a.m. UTC | #2
Hi, Jason.

Thanks a lot for your reply.

On 2018/12/5 2:35, Jason Gunthorpe wrote:
> On Sat, Nov 24, 2018 at 05:12:55PM +0800, Lijun Ou wrote:
>> From: Yangyang Li <liyangyang20@huawei.com>
>>
>> This patch adds qpc timer and cqc timer allocation
>> support for hardware timeout retransmission in
>> kernel space driver.
>>
>> Signed-off-by: Yangyang Li <liyangyang20@huawei.com>
>>  drivers/infiniband/hw/hns/hns_roce_cmd.h    |   8 +++
>>  drivers/infiniband/hw/hns/hns_roce_device.h |  28 ++++++++
>>  drivers/infiniband/hw/hns/hns_roce_hem.c    |  42 ++++++++++++
>>  drivers/infiniband/hw/hns/hns_roce_hem.h    |   2 +
>>  drivers/infiniband/hw/hns/hns_roce_hw_v2.c  | 103 +++++++++++++++++++++++++++-
>>  drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |  24 +++++++
>>  drivers/infiniband/hw/hns/hns_roce_main.c   |  36 ++++++++++
>>  7 files changed, 242 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h
>> index 5348282..97c5f2c 100644
>> +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h
>> @@ -93,6 +93,14 @@ enum {
>>  	HNS_ROCE_CMD_READ_SCC_CTX_BT0	= 0xa4,
>>  	HNS_ROCE_CMD_WRITE_SCC_CTX_BT0	= 0xa5,
>>  
>> +	/* QPC TIMER commands */
>> +	HNS_ROCE_CMD_WRITE_QPC_TIMER_BT0 = 0x33,
>> +	HNS_ROCE_CMD_READ_QPC_TIMER_BT0  = 0x37,
>> +
>> +	/* CQC TIMER commands */
>> +	HNS_ROCE_CMD_WRITE_CQC_TIMER_BT0 = 0x23,
>> +	HNS_ROCE_CMD_READ_CQC_TIMER_BT0  = 0x27,
>> +
>>  	/* EQC commands */
>>  	HNS_ROCE_CMD_CREATE_AEQC	= 0x80,
>>  	HNS_ROCE_CMD_MODIFY_AEQC	= 0x81,
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
>> index 6fe1871..2a66929 100644
>> +++ b/drivers/infiniband/hw/hns/hns_roce_device.h
>> @@ -486,6 +486,13 @@ struct hns_roce_qp_table {
>>  	struct hns_roce_hem_table	scc_ctx_table;
>>  };
>>  
>> +struct hns_roce_qpc_timer_table {
>> +	struct hns_roce_bitmap		bitmap;
>> +	spinlock_t			lock;
>> +	struct radix_tree_root		tree;
> 
> Same comment as for the SRQ patches, lets use xarray instead of adding
> new radix_tree users
ok, thanks.
> 
>> +	struct hns_roce_hem_table	table;
>> +};
>> +
>>  struct hns_roce_cq_table {
>>  	struct hns_roce_bitmap		bitmap;
>>  	spinlock_t			lock;
>> @@ -499,6 +506,13 @@ struct hns_roce_srq_table {
>>  	struct hns_roce_hem_table	table;
>>  };
>>  
>> +struct hns_roce_cqc_timer_table {
>> +	struct hns_roce_bitmap		bitmap;
>> +	spinlock_t			lock;
>> +	struct radix_tree_root		tree;
> 
> Here too
> 
> Although, I'm confused, this adds a new struct and a member called
> 'tree' but the word 'tree' does not appear in this patch otherwise. What is
> going on? Where is the user?
Yes, this is a defined but unused variable. After analysis, there is no plan
to use it now or in the future. So we decided to delete it.

Thanks.
> 
> Jason
> 
>
Yangyang Li Dec. 5, 2018, 9:16 a.m. UTC | #3
On 2018/12/5 2:35, Jason Gunthorpe wrote:
> On Sat, Nov 24, 2018 at 05:12:55PM +0800, Lijun Ou wrote:
>> From: Yangyang Li <liyangyang20@huawei.com>
>>
>> This patch adds qpc timer and cqc timer allocation
>> support for hardware timeout retransmission in
>> kernel space driver.
>>
>> Signed-off-by: Yangyang Li <liyangyang20@huawei.com>
>>  drivers/infiniband/hw/hns/hns_roce_cmd.h    |   8 +++
>>  drivers/infiniband/hw/hns/hns_roce_device.h |  28 ++++++++
>>  drivers/infiniband/hw/hns/hns_roce_hem.c    |  42 ++++++++++++
>>  drivers/infiniband/hw/hns/hns_roce_hem.h    |   2 +
>>  drivers/infiniband/hw/hns/hns_roce_hw_v2.c  | 103 +++++++++++++++++++++++++++-
>>  drivers/infiniband/hw/hns/hns_roce_hw_v2.h  |  24 +++++++
>>  drivers/infiniband/hw/hns/hns_roce_main.c   |  36 ++++++++++
>>  7 files changed, 242 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h
>> index 5348282..97c5f2c 100644
>> +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h
>> @@ -93,6 +93,14 @@ enum {
>>  	HNS_ROCE_CMD_READ_SCC_CTX_BT0	= 0xa4,
>>  	HNS_ROCE_CMD_WRITE_SCC_CTX_BT0	= 0xa5,
>>  
>> +	/* QPC TIMER commands */
>> +	HNS_ROCE_CMD_WRITE_QPC_TIMER_BT0 = 0x33,
>> +	HNS_ROCE_CMD_READ_QPC_TIMER_BT0  = 0x37,
>> +
>> +	/* CQC TIMER commands */
>> +	HNS_ROCE_CMD_WRITE_CQC_TIMER_BT0 = 0x23,
>> +	HNS_ROCE_CMD_READ_CQC_TIMER_BT0  = 0x27,
>> +
>>  	/* EQC commands */
>>  	HNS_ROCE_CMD_CREATE_AEQC	= 0x80,
>>  	HNS_ROCE_CMD_MODIFY_AEQC	= 0x81,
>> diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
>> index 6fe1871..2a66929 100644
>> +++ b/drivers/infiniband/hw/hns/hns_roce_device.h
>> @@ -486,6 +486,13 @@ struct hns_roce_qp_table {
>>  	struct hns_roce_hem_table	scc_ctx_table;
>>  };
>>  
>> +struct hns_roce_qpc_timer_table {
>> +	struct hns_roce_bitmap		bitmap;
>> +	spinlock_t			lock;
>> +	struct radix_tree_root		tree;
> 
> Same comment as for the SRQ patches, lets use xarray instead of adding
> new radix_tree users
> 
>> +	struct hns_roce_hem_table	table;
>> +};
>> +
>>  struct hns_roce_cq_table {
>>  	struct hns_roce_bitmap		bitmap;
>>  	spinlock_t			lock;
>> @@ -499,6 +506,13 @@ struct hns_roce_srq_table {
>>  	struct hns_roce_hem_table	table;
>>  };
>>  
>> +struct hns_roce_cqc_timer_table {
>> +	struct hns_roce_bitmap		bitmap;
>> +	spinlock_t			lock;
>> +	struct radix_tree_root		tree;
> 
> Here too
> 
> Although, I'm confused, this adds a new struct and a member called
> 'tree' but the word 'tree' does not appear in this patch otherwise. What is
> going on? Where is the user?
Hi, Jason.

Thanks a lot for your reply.

Only 'table' in struct hns_roce_cqc_timer_table was used in my driver.
'bitmap','lock' and 'tree' were not used.
So hns_roce_qpc_timer_table and hns_roce_cqc_timer_table should be deleted,
and replaced with struct hns_roce_hem_table.
Redundant code should not exist, I should pay more attention to this aspect.

Thanks.

> 
> Jason
> 
>
diff mbox series

Patch

diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h
index 5348282..97c5f2c 100644
--- a/drivers/infiniband/hw/hns/hns_roce_cmd.h
+++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h
@@ -93,6 +93,14 @@  enum {
 	HNS_ROCE_CMD_READ_SCC_CTX_BT0	= 0xa4,
 	HNS_ROCE_CMD_WRITE_SCC_CTX_BT0	= 0xa5,
 
+	/* QPC TIMER commands */
+	HNS_ROCE_CMD_WRITE_QPC_TIMER_BT0 = 0x33,
+	HNS_ROCE_CMD_READ_QPC_TIMER_BT0  = 0x37,
+
+	/* CQC TIMER commands */
+	HNS_ROCE_CMD_WRITE_CQC_TIMER_BT0 = 0x23,
+	HNS_ROCE_CMD_READ_CQC_TIMER_BT0  = 0x27,
+
 	/* EQC commands */
 	HNS_ROCE_CMD_CREATE_AEQC	= 0x80,
 	HNS_ROCE_CMD_MODIFY_AEQC	= 0x81,
diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h
index 6fe1871..2a66929 100644
--- a/drivers/infiniband/hw/hns/hns_roce_device.h
+++ b/drivers/infiniband/hw/hns/hns_roce_device.h
@@ -486,6 +486,13 @@  struct hns_roce_qp_table {
 	struct hns_roce_hem_table	scc_ctx_table;
 };
 
+struct hns_roce_qpc_timer_table {
+	struct hns_roce_bitmap		bitmap;
+	spinlock_t			lock;
+	struct radix_tree_root		tree;
+	struct hns_roce_hem_table	table;
+};
+
 struct hns_roce_cq_table {
 	struct hns_roce_bitmap		bitmap;
 	spinlock_t			lock;
@@ -499,6 +506,13 @@  struct hns_roce_srq_table {
 	struct hns_roce_hem_table	table;
 };
 
+struct hns_roce_cqc_timer_table {
+	struct hns_roce_bitmap		bitmap;
+	spinlock_t			lock;
+	struct radix_tree_root		tree;
+	struct hns_roce_hem_table	table;
+};
+
 struct hns_roce_raq_table {
 	struct hns_roce_buf_list	*e_raq_buf;
 };
@@ -731,6 +745,8 @@  struct hns_roce_caps {
 	u32		max_extend_sg;
 	int		num_qps;	/* 256k */
 	int             reserved_qps;
+	int		num_qpc_timer;
+	int		num_cqc_timer;
 	u32		max_srq_sg;
 	int		num_srqs;
 	u32		max_wqes;	/* 16k */
@@ -771,6 +787,8 @@  struct hns_roce_caps {
 	int		trrl_entry_sz;
 	int		cqc_entry_sz;
 	int		scc_ctx_entry_sz;
+	int		qpc_timer_entry_sz;
+	int		cqc_timer_entry_sz;
 	int		srqc_entry_sz;
 	int		idx_entry_sz;
 	u32		pbl_ba_pg_sz;
@@ -780,8 +798,10 @@  struct hns_roce_caps {
 	int		ceqe_depth;
 	enum ib_mtu	max_mtu;
 	u32		qpc_bt_num;
+	u32		qpc_timer_bt_num;
 	u32		srqc_bt_num;
 	u32		cqc_bt_num;
+	u32		cqc_timer_bt_num;
 	u32		mpt_bt_num;
 	u32		scc_ctx_bt_num;
 	u32		qpc_ba_pg_sz;
@@ -802,6 +822,12 @@  struct hns_roce_caps {
 	u32		scc_ctx_ba_pg_sz;
 	u32		scc_ctx_buf_pg_sz;
 	u32		scc_ctx_hop_num;
+	u32		qpc_timer_ba_pg_sz;
+	u32		qpc_timer_buf_pg_sz;
+	u32		qpc_timer_hop_num;
+	u32		cqc_timer_ba_pg_sz;
+	u32		cqc_timer_buf_pg_sz;
+	u32		cqc_timer_hop_num;
 	u32		cqe_ba_pg_sz;
 	u32		cqe_buf_pg_sz;
 	u32		cqe_hop_num;
@@ -929,6 +955,8 @@  struct hns_roce_dev {
 	struct hns_roce_srq_table srq_table;
 	struct hns_roce_qp_table  qp_table;
 	struct hns_roce_eq_table  eq_table;
+	struct hns_roce_qpc_timer_table  qpc_timer_table;
+	struct hns_roce_cqc_timer_table  cqc_timer_table;
 
 	int			cmd_mod;
 	int			loop_idc;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c
index 9e4a2ba..ab857e7 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.c
@@ -46,6 +46,8 @@  bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type)
 	    (hr_dev->caps.cqc_hop_num && type == HEM_TYPE_CQC) ||
 	    (hr_dev->caps.srqc_hop_num && type == HEM_TYPE_SRQC) ||
 	    (hr_dev->caps.scc_ctx_hop_num && type == HEM_TYPE_SCC_CTX) ||
+	    (hr_dev->caps.qpc_timer_hop_num && type == HEM_TYPE_QPC_TIMER) ||
+	    (hr_dev->caps.cqc_timer_hop_num && type == HEM_TYPE_CQC_TIMER) ||
 	    (hr_dev->caps.cqe_hop_num && type == HEM_TYPE_CQE) ||
 	    (hr_dev->caps.mtt_hop_num && type == HEM_TYPE_MTT) ||
 	    (hr_dev->caps.srqwqe_hop_num && type == HEM_TYPE_SRQWQE) ||
@@ -134,6 +136,22 @@  int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
 		mhop->ba_l0_num = hr_dev->caps.scc_ctx_bt_num;
 		mhop->hop_num = hr_dev->caps.scc_ctx_hop_num;
 		break;
+	case HEM_TYPE_QPC_TIMER:
+		mhop->buf_chunk_size = 1 << (hr_dev->caps.qpc_timer_buf_pg_sz
+					     + PAGE_SHIFT);
+		mhop->bt_chunk_size = 1 << (hr_dev->caps.qpc_timer_ba_pg_sz
+					    + PAGE_SHIFT);
+		mhop->ba_l0_num = hr_dev->caps.qpc_timer_bt_num;
+		mhop->hop_num = hr_dev->caps.qpc_timer_hop_num;
+		break;
+	case HEM_TYPE_CQC_TIMER:
+		mhop->buf_chunk_size = 1 << (hr_dev->caps.cqc_timer_buf_pg_sz
+					     + PAGE_SHIFT);
+		mhop->bt_chunk_size = 1 << (hr_dev->caps.cqc_timer_ba_pg_sz
+					    + PAGE_SHIFT);
+		mhop->ba_l0_num = hr_dev->caps.cqc_timer_bt_num;
+		mhop->hop_num = hr_dev->caps.cqc_timer_hop_num;
+		break;
 	case HEM_TYPE_SRQC:
 		mhop->buf_chunk_size = 1 << (hr_dev->caps.srqc_buf_pg_sz
 					     + PAGE_SHIFT);
@@ -602,6 +620,7 @@  int hns_roce_table_get(struct hns_roce_dev *hr_dev,
 	mutex_unlock(&table->mutex);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(hns_roce_table_get);
 
 static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev,
 				    struct hns_roce_hem_table *table,
@@ -744,6 +763,7 @@  void hns_roce_table_put(struct hns_roce_dev *hr_dev,
 
 	mutex_unlock(&table->mutex);
 }
+EXPORT_SYMBOL_GPL(hns_roce_table_put);
 
 void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
 			  struct hns_roce_hem_table *table,
@@ -921,6 +941,22 @@  int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
 			num_bt_l0 = hr_dev->caps.scc_ctx_bt_num;
 			hop_num = hr_dev->caps.scc_ctx_hop_num;
 			break;
+		case HEM_TYPE_QPC_TIMER:
+			buf_chunk_size = 1 << (hr_dev->caps.qpc_timer_buf_pg_sz
+					+ PAGE_SHIFT);
+			bt_chunk_size = 1 << (hr_dev->caps.qpc_timer_ba_pg_sz
+					+ PAGE_SHIFT);
+			num_bt_l0 = hr_dev->caps.qpc_timer_bt_num;
+			hop_num = hr_dev->caps.qpc_timer_hop_num;
+			break;
+		case HEM_TYPE_CQC_TIMER:
+			buf_chunk_size = 1 << (hr_dev->caps.cqc_timer_buf_pg_sz
+					+ PAGE_SHIFT);
+			bt_chunk_size = 1 << (hr_dev->caps.cqc_timer_ba_pg_sz
+					+ PAGE_SHIFT);
+			num_bt_l0 = hr_dev->caps.cqc_timer_bt_num;
+			hop_num = hr_dev->caps.cqc_timer_hop_num;
+			break;
 		case HEM_TYPE_SRQC:
 			buf_chunk_size = 1 << (hr_dev->caps.srqc_buf_pg_sz
 					+ PAGE_SHIFT);
@@ -1098,6 +1134,12 @@  void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev)
 		hns_roce_cleanup_hem_table(hr_dev,
 					   &hr_dev->srq_table.table);
 	hns_roce_cleanup_hem_table(hr_dev, &hr_dev->cq_table.table);
+	if (hr_dev->caps.qpc_timer_entry_sz)
+		hns_roce_cleanup_hem_table(hr_dev,
+					   &hr_dev->qpc_timer_table.table);
+	if (hr_dev->caps.cqc_timer_entry_sz)
+		hns_roce_cleanup_hem_table(hr_dev,
+					   &hr_dev->cqc_timer_table.table);
 	if (hr_dev->caps.scc_ctx_entry_sz)
 		hns_roce_cleanup_hem_table(hr_dev,
 					   &hr_dev->qp_table.scc_ctx_table);
diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.h b/drivers/infiniband/hw/hns/hns_roce_hem.h
index 6e4fe97..172af08 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hem.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hem.h
@@ -45,6 +45,8 @@  enum {
 	HEM_TYPE_CQC,
 	HEM_TYPE_SRQC,
 	HEM_TYPE_SCC_CTX,
+	HEM_TYPE_QPC_TIMER,
+	HEM_TYPE_CQC_TIMER,
 
 	 /* UNMAP HEM */
 	HEM_TYPE_MTT,
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
index 4520061..82e2ace 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.c
@@ -1085,6 +1085,42 @@  static int hns_roce_query_pf_resource(struct hns_roce_dev *hr_dev)
 	return 0;
 }
 
+static int hns_roce_query_pf_timer_resource(struct hns_roce_dev *hr_dev)
+{
+	struct hns_roce_cmq_desc desc[2];
+	struct hns_roce_pf_timer_res_a *req_a;
+	int ret;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		hns_roce_cmq_setup_basic_desc(&desc[i],
+					      HNS_ROCE_OPC_QUERY_PF_TIMER_RES,
+					      true);
+
+		if (i == 0)
+			desc[i].flag |= cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
+		else
+			desc[i].flag &= ~cpu_to_le16(HNS_ROCE_CMD_FLAG_NEXT);
+	}
+
+	ret = hns_roce_cmq_send(hr_dev, desc, 2);
+	if (ret)
+		return ret;
+
+	req_a = (struct hns_roce_pf_timer_res_a *)desc[0].data;
+
+	hr_dev->caps.qpc_timer_bt_num =
+				roce_get_field(req_a->qpc_timer_bt_idx_num,
+					PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_M,
+					PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_S);
+	hr_dev->caps.cqc_timer_bt_num =
+				roce_get_field(req_a->cqc_timer_bt_idx_num,
+					PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_M,
+					PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_S);
+
+	return 0;
+}
+
 static int hns_roce_alloc_vf_resource(struct hns_roce_dev *hr_dev)
 {
 	struct hns_roce_cmq_desc desc[2];
@@ -1280,6 +1316,16 @@  static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
 		return ret;
 	}
 
+	if (hr_dev->pci_dev->revision == 0x21) {
+		ret = hns_roce_query_pf_timer_resource(hr_dev);
+		if (ret) {
+			dev_err(hr_dev->dev,
+				"Query pf timer resource fail, ret = %d.\n",
+				ret);
+			return ret;
+		}
+	}
+
 	ret = hns_roce_alloc_vf_resource(hr_dev);
 	if (ret) {
 		dev_err(hr_dev->dev, "Allocate vf resource fail, ret = %d.\n",
@@ -1394,6 +1440,18 @@  static int hns_roce_v2_profile(struct hns_roce_dev *hr_dev)
 		caps->flags |= HNS_ROCE_CAP_FLAG_ATOMIC |
 			       HNS_ROCE_CAP_FLAG_SRQ |
 			       HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL;
+
+		caps->num_qpc_timer	  = HNS_ROCE_V2_MAX_QPC_TIMER_NUM;
+		caps->num_cqc_timer	  = HNS_ROCE_V2_MAX_CQC_TIMER_NUM;
+		caps->qpc_timer_entry_sz  = HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ;
+		caps->cqc_timer_entry_sz  = HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ;
+		caps->qpc_timer_ba_pg_sz  = 0;
+		caps->qpc_timer_buf_pg_sz = 0;
+		caps->qpc_timer_hop_num   = HNS_ROCE_HOP_NUM_0;
+		caps->cqc_timer_ba_pg_sz  = 0;
+		caps->cqc_timer_buf_pg_sz = 0;
+		caps->cqc_timer_hop_num   = HNS_ROCE_HOP_NUM_0;
+
 		caps->scc_ctx_entry_sz	= HNS_ROCE_V2_SCC_CTX_ENTRY_SZ;
 		caps->scc_ctx_ba_pg_sz	= 0;
 		caps->scc_ctx_buf_pg_sz = 0;
@@ -1599,7 +1657,10 @@  static void hns_roce_free_link_table(struct hns_roce_dev *hr_dev,
 static int hns_roce_v2_init(struct hns_roce_dev *hr_dev)
 {
 	struct hns_roce_v2_priv *priv = hr_dev->priv;
+	int qpc_count;
+	int cqc_count;
 	int ret;
+	int i;
 
 	/* TSQ includes SQ doorbell and ack doorbell */
 	ret = hns_roce_init_link_table(hr_dev, TSQ_LINK_TABLE);
@@ -1614,8 +1675,40 @@  static int hns_roce_v2_init(struct hns_roce_dev *hr_dev)
 		goto err_tpq_init_failed;
 	}
 
+	/* Alloc memory for QPC Timer buffer space chunk*/
+	for (qpc_count = 0; qpc_count < hr_dev->caps.qpc_timer_bt_num;
+	     qpc_count++) {
+		ret = hns_roce_table_get(hr_dev, &hr_dev->qpc_timer_table.table,
+					 qpc_count);
+		if (ret) {
+			dev_err(hr_dev->dev, "QPC Timer get failed\n");
+			goto err_qpc_timer_failed;
+		}
+	}
+
+	/* Alloc memory for CQC Timer buffer space chunk*/
+	for (cqc_count = 0; cqc_count < hr_dev->caps.cqc_timer_bt_num;
+	     cqc_count++) {
+		ret = hns_roce_table_get(hr_dev, &hr_dev->cqc_timer_table.table,
+					 cqc_count);
+		if (ret) {
+			dev_err(hr_dev->dev, "CQC Timer get failed\n");
+			goto err_cqc_timer_failed;
+		}
+	}
+
 	return 0;
 
+err_cqc_timer_failed:
+	for (i = 0; i < cqc_count; i++)
+		hns_roce_table_put(hr_dev, &hr_dev->cqc_timer_table.table, i);
+
+err_qpc_timer_failed:
+	for (i = 0; i < qpc_count; i++)
+		hns_roce_table_put(hr_dev, &hr_dev->qpc_timer_table.table, i);
+
+	hns_roce_free_link_table(hr_dev, &priv->tpq);
+
 err_tpq_init_failed:
 	hns_roce_free_link_table(hr_dev, &priv->tsq);
 
@@ -2649,6 +2742,12 @@  static int hns_roce_v2_set_hem(struct hns_roce_dev *hr_dev,
 		}
 		op = HNS_ROCE_CMD_WRITE_SCC_CTX_BT0;
 		break;
+	case HEM_TYPE_QPC_TIMER:
+		op = HNS_ROCE_CMD_WRITE_QPC_TIMER_BT0;
+		break;
+	case HEM_TYPE_CQC_TIMER:
+		op = HNS_ROCE_CMD_WRITE_CQC_TIMER_BT0;
+		break;
 	default:
 		dev_warn(dev, "Table %d not to be written by mailbox!\n",
 			 table->type);
@@ -2709,7 +2808,9 @@  static int hns_roce_v2_clear_hem(struct hns_roce_dev *hr_dev,
 		op = HNS_ROCE_CMD_DESTROY_CQC_BT0;
 		break;
 	case HEM_TYPE_SCC_CTX:
-		/* there is no need to destroy scc ctx */
+	case HEM_TYPE_QPC_TIMER:
+	case HEM_TYPE_CQC_TIMER:
+		/* there is no need to destroy these ctx */
 		return 0;
 	case HEM_TYPE_SRQC:
 		op = HNS_ROCE_CMD_DESTROY_SRQC_BT0;
diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
index bd9f086..e6e3d8fb 100644
--- a/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
+++ b/drivers/infiniband/hw/hns/hns_roce_hw_v2.h
@@ -45,11 +45,13 @@ 
 #define HNS_ROCE_VF_SL_NUM			8
 
 #define HNS_ROCE_V2_MAX_QP_NUM			0x2000
+#define HNS_ROCE_V2_MAX_QPC_TIMER_NUM          0x200
 #define HNS_ROCE_V2_MAX_WQE_NUM			0x8000
 #define	HNS_ROCE_V2_MAX_SRQ			0x100000
 #define HNS_ROCE_V2_MAX_SRQ_WR			0x8000
 #define HNS_ROCE_V2_MAX_SRQ_SGE			0x100
 #define HNS_ROCE_V2_MAX_CQ_NUM			0x8000
+#define HNS_ROCE_V2_MAX_CQC_TIMER_NUM          0x100
 #define HNS_ROCE_V2_MAX_SRQ_NUM			0x100000
 #define HNS_ROCE_V2_MAX_CQE_NUM			0x10000
 #define HNS_ROCE_V2_MAX_SRQWQE_NUM		0x8000
@@ -84,6 +86,8 @@ 
 #define HNS_ROCE_V2_MTT_ENTRY_SZ		64
 #define HNS_ROCE_V2_CQE_ENTRY_SIZE		32
 #define HNS_ROCE_V2_SCC_CTX_ENTRY_SZ		32
+#define HNS_ROCE_V2_QPC_TIMER_ENTRY_SZ		4096
+#define HNS_ROCE_V2_CQC_TIMER_ENTRY_SZ		4096
 #define HNS_ROCE_V2_PAGE_SIZE_SUPPORTED		0xFFFFF000
 #define HNS_ROCE_V2_MAX_INNER_MTPT_NUM		2
 #define HNS_ROCE_INVALID_LKEY			0x100
@@ -226,6 +230,7 @@  enum hns_roce_opcode_type {
 	HNS_ROCE_OPC_ALLOC_VF_RES			= 0x8401,
 	HNS_ROCE_OPC_CFG_EXT_LLM			= 0x8403,
 	HNS_ROCE_OPC_CFG_TMOUT_LLM			= 0x8404,
+	HNS_ROCE_OPC_QUERY_PF_TIMER_RES			= 0x8406,
 	HNS_ROCE_OPC_CFG_SGID_TB			= 0x8500,
 	HNS_ROCE_OPC_CFG_SMAC_TB			= 0x8501,
 	HNS_ROCE_OPC_CFG_BT_ATTR			= 0x8506,
@@ -1330,6 +1335,25 @@  struct hns_roce_pf_res_b {
 #define PF_RES_DATA_4_PF_SCC_CTX_BT_NUM_S 9
 #define PF_RES_DATA_4_PF_SCC_CTX_BT_NUM_M GENMASK(17, 9)
 
+struct hns_roce_pf_timer_res_a {
+	__le32	rsv0;
+	__le32	qpc_timer_bt_idx_num;
+	__le32	cqc_timer_bt_idx_num;
+	__le32	rsv[3];
+};
+
+#define PF_RES_DATA_1_PF_QPC_TIMER_BT_IDX_S 0
+#define PF_RES_DATA_1_PF_QPC_TIMER_BT_IDX_M GENMASK(11, 0)
+
+#define PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_S 16
+#define PF_RES_DATA_1_PF_QPC_TIMER_BT_NUM_M GENMASK(28, 16)
+
+#define PF_RES_DATA_2_PF_CQC_TIMER_BT_IDX_S 0
+#define PF_RES_DATA_2_PF_CQC_TIMER_BT_IDX_M GENMASK(10, 0)
+
+#define PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_S 16
+#define PF_RES_DATA_2_PF_CQC_TIMER_BT_NUM_M GENMASK(27, 16)
+
 struct hns_roce_vf_res_a {
 	__le32 vf_id;
 	__le32 vf_qpc_bt_idx_num;
diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c
index 199ab0d..68f22b8 100644
--- a/drivers/infiniband/hw/hns/hns_roce_main.c
+++ b/drivers/infiniband/hw/hns/hns_roce_main.c
@@ -717,8 +717,44 @@  static int hns_roce_init_hem(struct hns_roce_dev *hr_dev)
 		}
 	}
 
+	if (hr_dev->caps.qpc_timer_entry_sz) {
+		ret = hns_roce_init_hem_table(hr_dev,
+					      &hr_dev->qpc_timer_table.table,
+					      HEM_TYPE_QPC_TIMER,
+					      hr_dev->caps.qpc_timer_entry_sz,
+					      hr_dev->caps.num_qpc_timer, 1);
+		if (ret) {
+			dev_err(dev,
+			      "Failed to init QPC timer memory, aborting.\n");
+			goto err_unmap_ctx;
+		}
+	}
+
+	if (hr_dev->caps.cqc_timer_entry_sz) {
+		ret = hns_roce_init_hem_table(hr_dev,
+					      &hr_dev->cqc_timer_table.table,
+					      HEM_TYPE_CQC_TIMER,
+					      hr_dev->caps.cqc_timer_entry_sz,
+					      hr_dev->caps.num_cqc_timer, 1);
+		if (ret) {
+			dev_err(dev,
+			      "Failed to init CQC timer memory, aborting.\n");
+			goto err_unmap_qpc_timer;
+		}
+	}
+
 	return 0;
 
+err_unmap_qpc_timer:
+	if (hr_dev->caps.qpc_timer_entry_sz)
+		hns_roce_cleanup_hem_table(hr_dev,
+					   &hr_dev->qpc_timer_table.table);
+
+err_unmap_ctx:
+	if (hr_dev->caps.scc_ctx_entry_sz)
+		hns_roce_cleanup_hem_table(hr_dev,
+					   &hr_dev->qp_table.scc_ctx_table);
+
 err_unmap_idx:
 	if (hr_dev->caps.num_idx_segs)
 		hns_roce_cleanup_hem_table(hr_dev,