brintos

brintos / linux-shallow public Read only

0
0
Text · 36.2 KiB · c7c167e Raw
1447 lines · c
1/*2 * Copyright (c) 2016 Hisilicon Limited.3 * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.4 *5 * This software is available to you under a choice of one of two6 * licenses.  You may choose to be licensed under the terms of the GNU7 * General Public License (GPL) Version 2, available from the file8 * COPYING in the main directory of this source tree, or the9 * OpenIB.org BSD license below:10 *11 *     Redistribution and use in source and binary forms, with or12 *     without modification, are permitted provided that the following13 *     conditions are met:14 *15 *      - Redistributions of source code must retain the above16 *        copyright notice, this list of conditions and the following17 *        disclaimer.18 *19 *      - Redistributions in binary form must reproduce the above20 *        copyright notice, this list of conditions and the following21 *        disclaimer in the documentation and/or other materials22 *        provided with the distribution.23 *24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31 * SOFTWARE.32 */33 34#include "hns_roce_device.h"35#include "hns_roce_hem.h"36#include "hns_roce_common.h"37 38#define HEM_INDEX_BUF			BIT(0)39#define HEM_INDEX_L0			BIT(1)40#define HEM_INDEX_L1			BIT(2)41struct hns_roce_hem_index {42	u64 buf;43	u64 l0;44	u64 l1;45	u32 inited; /* indicate which index is available */46};47 48bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type)49{50	int hop_num = 0;51 52	switch (type) {53	case HEM_TYPE_QPC:54		hop_num = hr_dev->caps.qpc_hop_num;55		break;56	case HEM_TYPE_MTPT:57		hop_num = hr_dev->caps.mpt_hop_num;58		break;59	case HEM_TYPE_CQC:60		hop_num = hr_dev->caps.cqc_hop_num;61		break;62	case HEM_TYPE_SRQC:63		hop_num = hr_dev->caps.srqc_hop_num;64		break;65	case HEM_TYPE_SCCC:66		hop_num = hr_dev->caps.sccc_hop_num;67		break;68	case HEM_TYPE_QPC_TIMER:69		hop_num = hr_dev->caps.qpc_timer_hop_num;70		break;71	case HEM_TYPE_CQC_TIMER:72		hop_num = hr_dev->caps.cqc_timer_hop_num;73		break;74	case HEM_TYPE_GMV:75		hop_num = hr_dev->caps.gmv_hop_num;76		break;77	default:78		return false;79	}80 81	return hop_num;82}83 84static bool hns_roce_check_hem_null(struct hns_roce_hem **hem, u64 hem_idx,85				    u32 bt_chunk_num, u64 hem_max_num)86{87	u64 start_idx = round_down(hem_idx, bt_chunk_num);88	u64 check_max_num = start_idx + bt_chunk_num;89	u64 i;90 91	for (i = start_idx; (i < check_max_num) && (i < hem_max_num); i++)92		if (i != hem_idx && hem[i])93			return false;94 95	return true;96}97 98static bool hns_roce_check_bt_null(u64 **bt, u64 ba_idx, u32 bt_chunk_num)99{100	u64 start_idx = round_down(ba_idx, bt_chunk_num);101	int i;102 103	for (i = 0; i < bt_chunk_num; i++)104		if (i != ba_idx && bt[start_idx + i])105			return false;106 107	return true;108}109 110static int hns_roce_get_bt_num(u32 table_type, u32 hop_num)111{112	if (check_whether_bt_num_3(table_type, hop_num))113		return 3;114	else if (check_whether_bt_num_2(table_type, hop_num))115		return 2;116	else if (check_whether_bt_num_1(table_type, hop_num))117		return 1;118	else119		return 0;120}121 122static int get_hem_table_config(struct hns_roce_dev *hr_dev,123				struct hns_roce_hem_mhop *mhop,124				u32 type)125{126	struct device *dev = hr_dev->dev;127 128	switch (type) {129	case HEM_TYPE_QPC:130		mhop->buf_chunk_size = 1 << (hr_dev->caps.qpc_buf_pg_sz131					     + PAGE_SHIFT);132		mhop->bt_chunk_size = 1 << (hr_dev->caps.qpc_ba_pg_sz133					     + PAGE_SHIFT);134		mhop->ba_l0_num = hr_dev->caps.qpc_bt_num;135		mhop->hop_num = hr_dev->caps.qpc_hop_num;136		break;137	case HEM_TYPE_MTPT:138		mhop->buf_chunk_size = 1 << (hr_dev->caps.mpt_buf_pg_sz139					     + PAGE_SHIFT);140		mhop->bt_chunk_size = 1 << (hr_dev->caps.mpt_ba_pg_sz141					     + PAGE_SHIFT);142		mhop->ba_l0_num = hr_dev->caps.mpt_bt_num;143		mhop->hop_num = hr_dev->caps.mpt_hop_num;144		break;145	case HEM_TYPE_CQC:146		mhop->buf_chunk_size = 1 << (hr_dev->caps.cqc_buf_pg_sz147					     + PAGE_SHIFT);148		mhop->bt_chunk_size = 1 << (hr_dev->caps.cqc_ba_pg_sz149					    + PAGE_SHIFT);150		mhop->ba_l0_num = hr_dev->caps.cqc_bt_num;151		mhop->hop_num = hr_dev->caps.cqc_hop_num;152		break;153	case HEM_TYPE_SCCC:154		mhop->buf_chunk_size = 1 << (hr_dev->caps.sccc_buf_pg_sz155					     + PAGE_SHIFT);156		mhop->bt_chunk_size = 1 << (hr_dev->caps.sccc_ba_pg_sz157					    + PAGE_SHIFT);158		mhop->ba_l0_num = hr_dev->caps.sccc_bt_num;159		mhop->hop_num = hr_dev->caps.sccc_hop_num;160		break;161	case HEM_TYPE_QPC_TIMER:162		mhop->buf_chunk_size = 1 << (hr_dev->caps.qpc_timer_buf_pg_sz163					     + PAGE_SHIFT);164		mhop->bt_chunk_size = 1 << (hr_dev->caps.qpc_timer_ba_pg_sz165					    + PAGE_SHIFT);166		mhop->ba_l0_num = hr_dev->caps.qpc_timer_bt_num;167		mhop->hop_num = hr_dev->caps.qpc_timer_hop_num;168		break;169	case HEM_TYPE_CQC_TIMER:170		mhop->buf_chunk_size = 1 << (hr_dev->caps.cqc_timer_buf_pg_sz171					     + PAGE_SHIFT);172		mhop->bt_chunk_size = 1 << (hr_dev->caps.cqc_timer_ba_pg_sz173					    + PAGE_SHIFT);174		mhop->ba_l0_num = hr_dev->caps.cqc_timer_bt_num;175		mhop->hop_num = hr_dev->caps.cqc_timer_hop_num;176		break;177	case HEM_TYPE_SRQC:178		mhop->buf_chunk_size = 1 << (hr_dev->caps.srqc_buf_pg_sz179					     + PAGE_SHIFT);180		mhop->bt_chunk_size = 1 << (hr_dev->caps.srqc_ba_pg_sz181					     + PAGE_SHIFT);182		mhop->ba_l0_num = hr_dev->caps.srqc_bt_num;183		mhop->hop_num = hr_dev->caps.srqc_hop_num;184		break;185	case HEM_TYPE_GMV:186		mhop->buf_chunk_size = 1 << (hr_dev->caps.gmv_buf_pg_sz +187					     PAGE_SHIFT);188		mhop->bt_chunk_size = 1 << (hr_dev->caps.gmv_ba_pg_sz +189					    PAGE_SHIFT);190		mhop->ba_l0_num = hr_dev->caps.gmv_bt_num;191		mhop->hop_num = hr_dev->caps.gmv_hop_num;192		break;193	default:194		dev_err(dev, "table %u not support multi-hop addressing!\n",195			type);196		return -EINVAL;197	}198 199	return 0;200}201 202int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,203			   struct hns_roce_hem_table *table, unsigned long *obj,204			   struct hns_roce_hem_mhop *mhop)205{206	struct device *dev = hr_dev->dev;207	u32 chunk_ba_num;208	u32 chunk_size;209	u32 table_idx;210	u32 bt_num;211 212	if (get_hem_table_config(hr_dev, mhop, table->type))213		return -EINVAL;214 215	if (!obj)216		return 0;217 218	/*219	 * QPC/MTPT/CQC/SRQC/SCCC alloc hem for buffer pages.220	 * MTT/CQE alloc hem for bt pages.221	 */222	bt_num = hns_roce_get_bt_num(table->type, mhop->hop_num);223	chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;224	chunk_size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size :225			      mhop->bt_chunk_size;226	table_idx = *obj / (chunk_size / table->obj_size);227	switch (bt_num) {228	case 3:229		mhop->l2_idx = table_idx & (chunk_ba_num - 1);230		mhop->l1_idx = table_idx / chunk_ba_num & (chunk_ba_num - 1);231		mhop->l0_idx = (table_idx / chunk_ba_num) / chunk_ba_num;232		break;233	case 2:234		mhop->l1_idx = table_idx & (chunk_ba_num - 1);235		mhop->l0_idx = table_idx / chunk_ba_num;236		break;237	case 1:238		mhop->l0_idx = table_idx;239		break;240	default:241		dev_err(dev, "table %u not support hop_num = %u!\n",242			table->type, mhop->hop_num);243		return -EINVAL;244	}245	if (mhop->l0_idx >= mhop->ba_l0_num)246		mhop->l0_idx %= mhop->ba_l0_num;247 248	return 0;249}250 251static struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev,252					       unsigned long hem_alloc_size,253					       gfp_t gfp_mask)254{255	struct hns_roce_hem *hem;256	int order;257	void *buf;258 259	WARN_ON(gfp_mask & __GFP_HIGHMEM);260 261	order = get_order(hem_alloc_size);262	if (PAGE_SIZE << order != hem_alloc_size) {263		dev_err(hr_dev->dev, "invalid hem_alloc_size: %lu!\n",264			hem_alloc_size);265		return NULL;266	}267 268	hem = kmalloc(sizeof(*hem),269		      gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));270	if (!hem)271		return NULL;272 273	buf = dma_alloc_coherent(hr_dev->dev, hem_alloc_size,274				 &hem->dma, gfp_mask);275	if (!buf)276		goto fail;277 278	hem->buf = buf;279	hem->size = hem_alloc_size;280 281	return hem;282 283fail:284	kfree(hem);285	return NULL;286}287 288void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem)289{290	if (!hem)291		return;292 293	dma_free_coherent(hr_dev->dev, hem->size, hem->buf, hem->dma);294 295	kfree(hem);296}297 298static int calc_hem_config(struct hns_roce_dev *hr_dev,299			   struct hns_roce_hem_table *table, unsigned long obj,300			   struct hns_roce_hem_mhop *mhop,301			   struct hns_roce_hem_index *index)302{303	struct ib_device *ibdev = &hr_dev->ib_dev;304	unsigned long mhop_obj = obj;305	u32 l0_idx, l1_idx, l2_idx;306	u32 chunk_ba_num;307	u32 bt_num;308	int ret;309 310	ret = hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, mhop);311	if (ret)312		return ret;313 314	l0_idx = mhop->l0_idx;315	l1_idx = mhop->l1_idx;316	l2_idx = mhop->l2_idx;317	chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;318	bt_num = hns_roce_get_bt_num(table->type, mhop->hop_num);319	switch (bt_num) {320	case 3:321		index->l1 = l0_idx * chunk_ba_num + l1_idx;322		index->l0 = l0_idx;323		index->buf = l0_idx * chunk_ba_num * chunk_ba_num +324			     l1_idx * chunk_ba_num + l2_idx;325		break;326	case 2:327		index->l0 = l0_idx;328		index->buf = l0_idx * chunk_ba_num + l1_idx;329		break;330	case 1:331		index->buf = l0_idx;332		break;333	default:334		ibdev_err(ibdev, "table %u not support mhop.hop_num = %u!\n",335			  table->type, mhop->hop_num);336		return -EINVAL;337	}338 339	if (unlikely(index->buf >= table->num_hem)) {340		ibdev_err(ibdev, "table %u exceed hem limt idx %llu, max %lu!\n",341			  table->type, index->buf, table->num_hem);342		return -EINVAL;343	}344 345	return 0;346}347 348static void free_mhop_hem(struct hns_roce_dev *hr_dev,349			  struct hns_roce_hem_table *table,350			  struct hns_roce_hem_mhop *mhop,351			  struct hns_roce_hem_index *index)352{353	u32 bt_size = mhop->bt_chunk_size;354	struct device *dev = hr_dev->dev;355 356	if (index->inited & HEM_INDEX_BUF) {357		hns_roce_free_hem(hr_dev, table->hem[index->buf]);358		table->hem[index->buf] = NULL;359	}360 361	if (index->inited & HEM_INDEX_L1) {362		dma_free_coherent(dev, bt_size, table->bt_l1[index->l1],363				  table->bt_l1_dma_addr[index->l1]);364		table->bt_l1[index->l1] = NULL;365	}366 367	if (index->inited & HEM_INDEX_L0) {368		dma_free_coherent(dev, bt_size, table->bt_l0[index->l0],369				  table->bt_l0_dma_addr[index->l0]);370		table->bt_l0[index->l0] = NULL;371	}372}373 374static int alloc_mhop_hem(struct hns_roce_dev *hr_dev,375			  struct hns_roce_hem_table *table,376			  struct hns_roce_hem_mhop *mhop,377			  struct hns_roce_hem_index *index)378{379	u32 bt_size = mhop->bt_chunk_size;380	struct device *dev = hr_dev->dev;381	gfp_t flag;382	u64 bt_ba;383	u32 size;384	int ret;385 386	/* alloc L1 BA's chunk */387	if ((check_whether_bt_num_3(table->type, mhop->hop_num) ||388	     check_whether_bt_num_2(table->type, mhop->hop_num)) &&389	     !table->bt_l0[index->l0]) {390		table->bt_l0[index->l0] = dma_alloc_coherent(dev, bt_size,391					    &table->bt_l0_dma_addr[index->l0],392					    GFP_KERNEL);393		if (!table->bt_l0[index->l0]) {394			ret = -ENOMEM;395			goto out;396		}397		index->inited |= HEM_INDEX_L0;398	}399 400	/* alloc L2 BA's chunk */401	if (check_whether_bt_num_3(table->type, mhop->hop_num) &&402	    !table->bt_l1[index->l1])  {403		table->bt_l1[index->l1] = dma_alloc_coherent(dev, bt_size,404					    &table->bt_l1_dma_addr[index->l1],405					    GFP_KERNEL);406		if (!table->bt_l1[index->l1]) {407			ret = -ENOMEM;408			goto err_alloc_hem;409		}410		index->inited |= HEM_INDEX_L1;411		*(table->bt_l0[index->l0] + mhop->l1_idx) =412					       table->bt_l1_dma_addr[index->l1];413	}414 415	/*416	 * alloc buffer space chunk for QPC/MTPT/CQC/SRQC/SCCC.417	 * alloc bt space chunk for MTT/CQE.418	 */419	size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size : bt_size;420	flag = GFP_KERNEL | __GFP_NOWARN;421	table->hem[index->buf] = hns_roce_alloc_hem(hr_dev, size, flag);422	if (!table->hem[index->buf]) {423		ret = -ENOMEM;424		goto err_alloc_hem;425	}426 427	index->inited |= HEM_INDEX_BUF;428	bt_ba = table->hem[index->buf]->dma;429 430	if (table->type < HEM_TYPE_MTT) {431		if (mhop->hop_num == 2)432			*(table->bt_l1[index->l1] + mhop->l2_idx) = bt_ba;433		else if (mhop->hop_num == 1)434			*(table->bt_l0[index->l0] + mhop->l1_idx) = bt_ba;435	} else if (mhop->hop_num == 2) {436		*(table->bt_l0[index->l0] + mhop->l1_idx) = bt_ba;437	}438 439	return 0;440err_alloc_hem:441	free_mhop_hem(hr_dev, table, mhop, index);442out:443	return ret;444}445 446static int set_mhop_hem(struct hns_roce_dev *hr_dev,447			struct hns_roce_hem_table *table, unsigned long obj,448			struct hns_roce_hem_mhop *mhop,449			struct hns_roce_hem_index *index)450{451	struct ib_device *ibdev = &hr_dev->ib_dev;452	u32 step_idx;453	int ret = 0;454 455	if (index->inited & HEM_INDEX_L0) {456		ret = hr_dev->hw->set_hem(hr_dev, table, obj, 0);457		if (ret) {458			ibdev_err(ibdev, "set HEM step 0 failed!\n");459			goto out;460		}461	}462 463	if (index->inited & HEM_INDEX_L1) {464		ret = hr_dev->hw->set_hem(hr_dev, table, obj, 1);465		if (ret) {466			ibdev_err(ibdev, "set HEM step 1 failed!\n");467			goto out;468		}469	}470 471	if (index->inited & HEM_INDEX_BUF) {472		if (mhop->hop_num == HNS_ROCE_HOP_NUM_0)473			step_idx = 0;474		else475			step_idx = mhop->hop_num;476		ret = hr_dev->hw->set_hem(hr_dev, table, obj, step_idx);477		if (ret)478			ibdev_err(ibdev, "set HEM step last failed!\n");479	}480out:481	return ret;482}483 484static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev,485				   struct hns_roce_hem_table *table,486				   unsigned long obj)487{488	struct ib_device *ibdev = &hr_dev->ib_dev;489	struct hns_roce_hem_index index = {};490	struct hns_roce_hem_mhop mhop = {};491	int ret;492 493	ret = calc_hem_config(hr_dev, table, obj, &mhop, &index);494	if (ret) {495		ibdev_err(ibdev, "calc hem config failed!\n");496		return ret;497	}498 499	mutex_lock(&table->mutex);500	if (table->hem[index.buf]) {501		refcount_inc(&table->hem[index.buf]->refcount);502		goto out;503	}504 505	ret = alloc_mhop_hem(hr_dev, table, &mhop, &index);506	if (ret) {507		ibdev_err(ibdev, "alloc mhop hem failed!\n");508		goto out;509	}510 511	/* set HEM base address to hardware */512	if (table->type < HEM_TYPE_MTT) {513		ret = set_mhop_hem(hr_dev, table, obj, &mhop, &index);514		if (ret) {515			ibdev_err(ibdev, "set HEM address to HW failed!\n");516			goto err_alloc;517		}518	}519 520	refcount_set(&table->hem[index.buf]->refcount, 1);521	goto out;522 523err_alloc:524	free_mhop_hem(hr_dev, table, &mhop, &index);525out:526	mutex_unlock(&table->mutex);527	return ret;528}529 530int hns_roce_table_get(struct hns_roce_dev *hr_dev,531		       struct hns_roce_hem_table *table, unsigned long obj)532{533	struct device *dev = hr_dev->dev;534	unsigned long i;535	int ret = 0;536 537	if (hns_roce_check_whether_mhop(hr_dev, table->type))538		return hns_roce_table_mhop_get(hr_dev, table, obj);539 540	i = obj / (table->table_chunk_size / table->obj_size);541 542	mutex_lock(&table->mutex);543 544	if (table->hem[i]) {545		refcount_inc(&table->hem[i]->refcount);546		goto out;547	}548 549	table->hem[i] = hns_roce_alloc_hem(hr_dev,550				       table->table_chunk_size,551				       GFP_KERNEL | __GFP_NOWARN);552	if (!table->hem[i]) {553		ret = -ENOMEM;554		goto out;555	}556 557	/* Set HEM base address(128K/page, pa) to Hardware */558	ret = hr_dev->hw->set_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT);559	if (ret) {560		hns_roce_free_hem(hr_dev, table->hem[i]);561		table->hem[i] = NULL;562		dev_err(dev, "set HEM base address to HW failed, ret = %d.\n",563			ret);564		goto out;565	}566 567	refcount_set(&table->hem[i]->refcount, 1);568out:569	mutex_unlock(&table->mutex);570	return ret;571}572 573static void clear_mhop_hem(struct hns_roce_dev *hr_dev,574			   struct hns_roce_hem_table *table, unsigned long obj,575			   struct hns_roce_hem_mhop *mhop,576			   struct hns_roce_hem_index *index)577{578	struct ib_device *ibdev = &hr_dev->ib_dev;579	u32 hop_num = mhop->hop_num;580	u32 chunk_ba_num;581	u32 step_idx;582	int ret;583 584	index->inited = HEM_INDEX_BUF;585	chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;586	if (check_whether_bt_num_2(table->type, hop_num)) {587		if (hns_roce_check_hem_null(table->hem, index->buf,588					    chunk_ba_num, table->num_hem))589			index->inited |= HEM_INDEX_L0;590	} else if (check_whether_bt_num_3(table->type, hop_num)) {591		if (hns_roce_check_hem_null(table->hem, index->buf,592					    chunk_ba_num, table->num_hem)) {593			index->inited |= HEM_INDEX_L1;594			if (hns_roce_check_bt_null(table->bt_l1, index->l1,595						   chunk_ba_num))596				index->inited |= HEM_INDEX_L0;597		}598	}599 600	if (table->type < HEM_TYPE_MTT) {601		if (hop_num == HNS_ROCE_HOP_NUM_0)602			step_idx = 0;603		else604			step_idx = hop_num;605 606		ret = hr_dev->hw->clear_hem(hr_dev, table, obj, step_idx);607		if (ret)608			ibdev_warn(ibdev, "failed to clear hop%u HEM, ret = %d.\n",609				   hop_num, ret);610 611		if (index->inited & HEM_INDEX_L1) {612			ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 1);613			if (ret)614				ibdev_warn(ibdev, "failed to clear HEM step 1, ret = %d.\n",615					   ret);616		}617 618		if (index->inited & HEM_INDEX_L0) {619			ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0);620			if (ret)621				ibdev_warn(ibdev, "failed to clear HEM step 0, ret = %d.\n",622					   ret);623		}624	}625}626 627static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev,628				    struct hns_roce_hem_table *table,629				    unsigned long obj,630				    int check_refcount)631{632	struct ib_device *ibdev = &hr_dev->ib_dev;633	struct hns_roce_hem_index index = {};634	struct hns_roce_hem_mhop mhop = {};635	int ret;636 637	ret = calc_hem_config(hr_dev, table, obj, &mhop, &index);638	if (ret) {639		ibdev_err(ibdev, "calc hem config failed!\n");640		return;641	}642 643	if (!check_refcount)644		mutex_lock(&table->mutex);645	else if (!refcount_dec_and_mutex_lock(&table->hem[index.buf]->refcount,646					      &table->mutex))647		return;648 649	clear_mhop_hem(hr_dev, table, obj, &mhop, &index);650	free_mhop_hem(hr_dev, table, &mhop, &index);651 652	mutex_unlock(&table->mutex);653}654 655void hns_roce_table_put(struct hns_roce_dev *hr_dev,656			struct hns_roce_hem_table *table, unsigned long obj)657{658	struct device *dev = hr_dev->dev;659	unsigned long i;660	int ret;661 662	if (hns_roce_check_whether_mhop(hr_dev, table->type)) {663		hns_roce_table_mhop_put(hr_dev, table, obj, 1);664		return;665	}666 667	i = obj / (table->table_chunk_size / table->obj_size);668 669	if (!refcount_dec_and_mutex_lock(&table->hem[i]->refcount,670					 &table->mutex))671		return;672 673	ret = hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT);674	if (ret)675		dev_warn(dev, "failed to clear HEM base address, ret = %d.\n",676			 ret);677 678	hns_roce_free_hem(hr_dev, table->hem[i]);679	table->hem[i] = NULL;680 681	mutex_unlock(&table->mutex);682}683 684void *hns_roce_table_find(struct hns_roce_dev *hr_dev,685			  struct hns_roce_hem_table *table,686			  unsigned long obj, dma_addr_t *dma_handle)687{688	struct hns_roce_hem_mhop mhop;689	struct hns_roce_hem *hem;690	unsigned long mhop_obj = obj;691	unsigned long obj_per_chunk;692	unsigned long idx_offset;693	int offset, dma_offset;694	void *addr = NULL;695	u32 hem_idx = 0;696	int i, j;697 698	mutex_lock(&table->mutex);699 700	if (!hns_roce_check_whether_mhop(hr_dev, table->type)) {701		obj_per_chunk = table->table_chunk_size / table->obj_size;702		hem = table->hem[obj / obj_per_chunk];703		idx_offset = obj % obj_per_chunk;704		dma_offset = offset = idx_offset * table->obj_size;705	} else {706		u32 seg_size = 64; /* 8 bytes per BA and 8 BA per segment */707 708		if (hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, &mhop))709			goto out;710		/* mtt mhop */711		i = mhop.l0_idx;712		j = mhop.l1_idx;713		if (mhop.hop_num == 2)714			hem_idx = i * (mhop.bt_chunk_size / BA_BYTE_LEN) + j;715		else if (mhop.hop_num == 1 ||716			 mhop.hop_num == HNS_ROCE_HOP_NUM_0)717			hem_idx = i;718 719		hem = table->hem[hem_idx];720		dma_offset = offset = obj * seg_size % mhop.bt_chunk_size;721		if (mhop.hop_num == 2)722			dma_offset = offset = 0;723	}724 725	if (!hem)726		goto out;727 728	*dma_handle = hem->dma + dma_offset;729	addr = hem->buf + offset;730 731out:732	mutex_unlock(&table->mutex);733	return addr;734}735 736int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,737			    struct hns_roce_hem_table *table, u32 type,738			    unsigned long obj_size, unsigned long nobj)739{740	unsigned long obj_per_chunk;741	unsigned long num_hem;742 743	if (!hns_roce_check_whether_mhop(hr_dev, type)) {744		table->table_chunk_size = hr_dev->caps.chunk_sz;745		obj_per_chunk = table->table_chunk_size / obj_size;746		num_hem = DIV_ROUND_UP(nobj, obj_per_chunk);747 748		table->hem = kcalloc(num_hem, sizeof(*table->hem), GFP_KERNEL);749		if (!table->hem)750			return -ENOMEM;751	} else {752		struct hns_roce_hem_mhop mhop = {};753		unsigned long buf_chunk_size;754		unsigned long bt_chunk_size;755		unsigned long bt_chunk_num;756		unsigned long num_bt_l0;757		u32 hop_num;758 759		if (get_hem_table_config(hr_dev, &mhop, type))760			return -EINVAL;761 762		buf_chunk_size = mhop.buf_chunk_size;763		bt_chunk_size = mhop.bt_chunk_size;764		num_bt_l0 = mhop.ba_l0_num;765		hop_num = mhop.hop_num;766 767		obj_per_chunk = buf_chunk_size / obj_size;768		num_hem = DIV_ROUND_UP(nobj, obj_per_chunk);769		bt_chunk_num = bt_chunk_size / BA_BYTE_LEN;770 771		if (type >= HEM_TYPE_MTT)772			num_bt_l0 = bt_chunk_num;773 774		table->hem = kcalloc(num_hem, sizeof(*table->hem),775					 GFP_KERNEL);776		if (!table->hem)777			goto err_kcalloc_hem_buf;778 779		if (check_whether_bt_num_3(type, hop_num)) {780			unsigned long num_bt_l1;781 782			num_bt_l1 = DIV_ROUND_UP(num_hem, bt_chunk_num);783			table->bt_l1 = kcalloc(num_bt_l1,784					       sizeof(*table->bt_l1),785					       GFP_KERNEL);786			if (!table->bt_l1)787				goto err_kcalloc_bt_l1;788 789			table->bt_l1_dma_addr = kcalloc(num_bt_l1,790						 sizeof(*table->bt_l1_dma_addr),791						 GFP_KERNEL);792 793			if (!table->bt_l1_dma_addr)794				goto err_kcalloc_l1_dma;795		}796 797		if (check_whether_bt_num_2(type, hop_num) ||798			check_whether_bt_num_3(type, hop_num)) {799			table->bt_l0 = kcalloc(num_bt_l0, sizeof(*table->bt_l0),800					       GFP_KERNEL);801			if (!table->bt_l0)802				goto err_kcalloc_bt_l0;803 804			table->bt_l0_dma_addr = kcalloc(num_bt_l0,805						 sizeof(*table->bt_l0_dma_addr),806						 GFP_KERNEL);807			if (!table->bt_l0_dma_addr)808				goto err_kcalloc_l0_dma;809		}810	}811 812	table->type = type;813	table->num_hem = num_hem;814	table->obj_size = obj_size;815	mutex_init(&table->mutex);816 817	return 0;818 819err_kcalloc_l0_dma:820	kfree(table->bt_l0);821	table->bt_l0 = NULL;822 823err_kcalloc_bt_l0:824	kfree(table->bt_l1_dma_addr);825	table->bt_l1_dma_addr = NULL;826 827err_kcalloc_l1_dma:828	kfree(table->bt_l1);829	table->bt_l1 = NULL;830 831err_kcalloc_bt_l1:832	kfree(table->hem);833	table->hem = NULL;834 835err_kcalloc_hem_buf:836	return -ENOMEM;837}838 839static void hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev *hr_dev,840					    struct hns_roce_hem_table *table)841{842	struct hns_roce_hem_mhop mhop;843	u32 buf_chunk_size;844	u64 obj;845	int i;846 847	if (hns_roce_calc_hem_mhop(hr_dev, table, NULL, &mhop))848		return;849	buf_chunk_size = table->type < HEM_TYPE_MTT ? mhop.buf_chunk_size :850					mhop.bt_chunk_size;851 852	for (i = 0; i < table->num_hem; ++i) {853		obj = i * buf_chunk_size / table->obj_size;854		if (table->hem[i])855			hns_roce_table_mhop_put(hr_dev, table, obj, 0);856	}857 858	kfree(table->hem);859	table->hem = NULL;860	kfree(table->bt_l1);861	table->bt_l1 = NULL;862	kfree(table->bt_l1_dma_addr);863	table->bt_l1_dma_addr = NULL;864	kfree(table->bt_l0);865	table->bt_l0 = NULL;866	kfree(table->bt_l0_dma_addr);867	table->bt_l0_dma_addr = NULL;868}869 870void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev,871				struct hns_roce_hem_table *table)872{873	struct device *dev = hr_dev->dev;874	unsigned long i;875	int obj;876	int ret;877 878	if (hns_roce_check_whether_mhop(hr_dev, table->type)) {879		hns_roce_cleanup_mhop_hem_table(hr_dev, table);880		mutex_destroy(&table->mutex);881		return;882	}883 884	for (i = 0; i < table->num_hem; ++i)885		if (table->hem[i]) {886			obj = i * table->table_chunk_size / table->obj_size;887			ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0);888			if (ret)889				dev_err(dev, "clear HEM base address failed, ret = %d.\n",890					ret);891 892			hns_roce_free_hem(hr_dev, table->hem[i]);893		}894 895	mutex_destroy(&table->mutex);896	kfree(table->hem);897}898 899void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev)900{901	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ)902		hns_roce_cleanup_hem_table(hr_dev,903					   &hr_dev->srq_table.table);904	hns_roce_cleanup_hem_table(hr_dev, &hr_dev->cq_table.table);905	if (hr_dev->caps.qpc_timer_entry_sz)906		hns_roce_cleanup_hem_table(hr_dev,907					   &hr_dev->qpc_timer_table);908	if (hr_dev->caps.cqc_timer_entry_sz)909		hns_roce_cleanup_hem_table(hr_dev,910					   &hr_dev->cqc_timer_table);911	if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL)912		hns_roce_cleanup_hem_table(hr_dev,913					   &hr_dev->qp_table.sccc_table);914	if (hr_dev->caps.trrl_entry_sz)915		hns_roce_cleanup_hem_table(hr_dev,916					   &hr_dev->qp_table.trrl_table);917 918	if (hr_dev->caps.gmv_entry_sz)919		hns_roce_cleanup_hem_table(hr_dev, &hr_dev->gmv_table);920 921	hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.irrl_table);922	hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.qp_table);923	hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table);924}925 926struct hns_roce_hem_item {927	struct list_head list; /* link all hems in the same bt level */928	struct list_head sibling; /* link all hems in last hop for mtt */929	void *addr;930	dma_addr_t dma_addr;931	size_t count; /* max ba numbers */932	int start; /* start buf offset in this hem */933	int end; /* end buf offset in this hem */934};935 936/* All HEM items are linked in a tree structure */937struct hns_roce_hem_head {938	struct list_head branch[HNS_ROCE_MAX_BT_REGION];939	struct list_head root;940	struct list_head leaf;941};942 943static struct hns_roce_hem_item *944hem_list_alloc_item(struct hns_roce_dev *hr_dev, int start, int end, int count,945		    bool exist_bt)946{947	struct hns_roce_hem_item *hem;948 949	hem = kzalloc(sizeof(*hem), GFP_KERNEL);950	if (!hem)951		return NULL;952 953	if (exist_bt) {954		hem->addr = dma_alloc_coherent(hr_dev->dev, count * BA_BYTE_LEN,955					       &hem->dma_addr, GFP_KERNEL);956		if (!hem->addr) {957			kfree(hem);958			return NULL;959		}960	}961 962	hem->count = count;963	hem->start = start;964	hem->end = end;965	INIT_LIST_HEAD(&hem->list);966	INIT_LIST_HEAD(&hem->sibling);967 968	return hem;969}970 971static void hem_list_free_item(struct hns_roce_dev *hr_dev,972			       struct hns_roce_hem_item *hem, bool exist_bt)973{974	if (exist_bt)975		dma_free_coherent(hr_dev->dev, hem->count * BA_BYTE_LEN,976				  hem->addr, hem->dma_addr);977	kfree(hem);978}979 980static void hem_list_free_all(struct hns_roce_dev *hr_dev,981			      struct list_head *head, bool exist_bt)982{983	struct hns_roce_hem_item *hem, *temp_hem;984 985	list_for_each_entry_safe(hem, temp_hem, head, list) {986		list_del(&hem->list);987		hem_list_free_item(hr_dev, hem, exist_bt);988	}989}990 991static void hem_list_link_bt(void *base_addr, u64 table_addr)992{993	*(u64 *)(base_addr) = table_addr;994}995 996/* assign L0 table address to hem from root bt */997static void hem_list_assign_bt(struct hns_roce_hem_item *hem, void *cpu_addr,998			       u64 phy_addr)999{1000	hem->addr = cpu_addr;1001	hem->dma_addr = (dma_addr_t)phy_addr;1002}1003 1004static inline bool hem_list_page_is_in_range(struct hns_roce_hem_item *hem,1005					     int offset)1006{1007	return (hem->start <= offset && offset <= hem->end);1008}1009 1010static struct hns_roce_hem_item *hem_list_search_item(struct list_head *ba_list,1011						      int page_offset)1012{1013	struct hns_roce_hem_item *hem, *temp_hem;1014	struct hns_roce_hem_item *found = NULL;1015 1016	list_for_each_entry_safe(hem, temp_hem, ba_list, list) {1017		if (hem_list_page_is_in_range(hem, page_offset)) {1018			found = hem;1019			break;1020		}1021	}1022 1023	return found;1024}1025 1026static bool hem_list_is_bottom_bt(int hopnum, int bt_level)1027{1028	/*1029	 * hopnum    base address table levels1030	 * 0		L0(buf)1031	 * 1		L0 -> buf1032	 * 2		L0 -> L1 -> buf1033	 * 3		L0 -> L1 -> L2 -> buf1034	 */1035	return bt_level >= (hopnum ? hopnum - 1 : hopnum);1036}1037 1038/*1039 * calc base address entries num1040 * @hopnum: num of mutihop addressing1041 * @bt_level: base address table level1042 * @unit: ba entries per bt page1043 */1044static u64 hem_list_calc_ba_range(int hopnum, int bt_level, int unit)1045{1046	u64 step;1047	int max;1048	int i;1049 1050	if (hopnum <= bt_level)1051		return 0;1052	/*1053	 * hopnum  bt_level   range1054	 * 1	      0       unit1055	 * ------------1056	 * 2	      0       unit * unit1057	 * 2	      1       unit1058	 * ------------1059	 * 3	      0       unit * unit * unit1060	 * 3	      1       unit * unit1061	 * 3	      2       unit1062	 */1063	step = 1;1064	max = hopnum - bt_level;1065	for (i = 0; i < max; i++)1066		step = step * unit;1067 1068	return step;1069}1070 1071/*1072 * calc the root ba entries which could cover all regions1073 * @regions: buf region array1074 * @region_cnt: array size of @regions1075 * @unit: ba entries per bt page1076 */1077int hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region *regions,1078				   int region_cnt, int unit)1079{1080	struct hns_roce_buf_region *r;1081	int total = 0;1082	u64 step;1083	int i;1084 1085	for (i = 0; i < region_cnt; i++) {1086		r = (struct hns_roce_buf_region *)&regions[i];1087		if (r->hopnum > 1) {1088			step = hem_list_calc_ba_range(r->hopnum, 1, unit);1089			if (step > 0)1090				total += (r->count + step - 1) / step;1091		} else {1092			total += r->count;1093		}1094	}1095 1096	return total;1097}1098 1099static int hem_list_alloc_mid_bt(struct hns_roce_dev *hr_dev,1100				 const struct hns_roce_buf_region *r, int unit,1101				 int offset, struct list_head *mid_bt,1102				 struct list_head *btm_bt)1103{1104	struct hns_roce_hem_item *hem_ptrs[HNS_ROCE_MAX_BT_LEVEL] = { NULL };1105	struct list_head temp_list[HNS_ROCE_MAX_BT_LEVEL];1106	struct hns_roce_hem_item *cur, *pre;1107	const int hopnum = r->hopnum;1108	int start_aligned;1109	int distance;1110	int ret = 0;1111	int max_ofs;1112	int level;1113	u64 step;1114	int end;1115 1116	if (hopnum <= 1)1117		return 0;1118 1119	if (hopnum > HNS_ROCE_MAX_BT_LEVEL) {1120		dev_err(hr_dev->dev, "invalid hopnum %d!\n", hopnum);1121		return -EINVAL;1122	}1123 1124	if (offset < r->offset) {1125		dev_err(hr_dev->dev, "invalid offset %d, min %u!\n",1126			offset, r->offset);1127		return -EINVAL;1128	}1129 1130	distance = offset - r->offset;1131	max_ofs = r->offset + r->count - 1;1132	for (level = 0; level < hopnum; level++)1133		INIT_LIST_HEAD(&temp_list[level]);1134 1135	/* config L1 bt to last bt and link them to corresponding parent */1136	for (level = 1; level < hopnum; level++) {1137		if (!hem_list_is_bottom_bt(hopnum, level)) {1138			cur = hem_list_search_item(&mid_bt[level], offset);1139			if (cur) {1140				hem_ptrs[level] = cur;1141				continue;1142			}1143		}1144 1145		step = hem_list_calc_ba_range(hopnum, level, unit);1146		if (step < 1) {1147			ret = -EINVAL;1148			goto err_exit;1149		}1150 1151		start_aligned = (distance / step) * step + r->offset;1152		end = min_t(u64, start_aligned + step - 1, max_ofs);1153		cur = hem_list_alloc_item(hr_dev, start_aligned, end, unit,1154					  true);1155		if (!cur) {1156			ret = -ENOMEM;1157			goto err_exit;1158		}1159		hem_ptrs[level] = cur;1160		list_add(&cur->list, &temp_list[level]);1161		if (hem_list_is_bottom_bt(hopnum, level))1162			list_add(&cur->sibling, &temp_list[0]);1163 1164		/* link bt to parent bt */1165		if (level > 1) {1166			pre = hem_ptrs[level - 1];1167			step = (cur->start - pre->start) / step * BA_BYTE_LEN;1168			hem_list_link_bt(pre->addr + step, cur->dma_addr);1169		}1170	}1171 1172	list_splice(&temp_list[0], btm_bt);1173	for (level = 1; level < hopnum; level++)1174		list_splice(&temp_list[level], &mid_bt[level]);1175 1176	return 0;1177 1178err_exit:1179	for (level = 1; level < hopnum; level++)1180		hem_list_free_all(hr_dev, &temp_list[level], true);1181 1182	return ret;1183}1184 1185static struct hns_roce_hem_item *1186alloc_root_hem(struct hns_roce_dev *hr_dev, int unit, int *max_ba_num,1187	       const struct hns_roce_buf_region *regions, int region_cnt)1188{1189	const struct hns_roce_buf_region *r;1190	struct hns_roce_hem_item *hem;1191	int ba_num;1192	int offset;1193 1194	ba_num = hns_roce_hem_list_calc_root_ba(regions, region_cnt, unit);1195	if (ba_num < 1)1196		return ERR_PTR(-ENOMEM);1197 1198	if (ba_num > unit)1199		return ERR_PTR(-ENOBUFS);1200 1201	offset = regions[0].offset;1202	/* indicate to last region */1203	r = &regions[region_cnt - 1];1204	hem = hem_list_alloc_item(hr_dev, offset, r->offset + r->count - 1,1205				  ba_num, true);1206	if (!hem)1207		return ERR_PTR(-ENOMEM);1208 1209	*max_ba_num = ba_num;1210 1211	return hem;1212}1213 1214static int alloc_fake_root_bt(struct hns_roce_dev *hr_dev, void *cpu_base,1215			      u64 phy_base, const struct hns_roce_buf_region *r,1216			      struct list_head *branch_head,1217			      struct list_head *leaf_head)1218{1219	struct hns_roce_hem_item *hem;1220 1221	hem = hem_list_alloc_item(hr_dev, r->offset, r->offset + r->count - 1,1222				  r->count, false);1223	if (!hem)1224		return -ENOMEM;1225 1226	hem_list_assign_bt(hem, cpu_base, phy_base);1227	list_add(&hem->list, branch_head);1228	list_add(&hem->sibling, leaf_head);1229 1230	return r->count;1231}1232 1233static int setup_middle_bt(struct hns_roce_dev *hr_dev, void *cpu_base,1234			   int unit, const struct hns_roce_buf_region *r,1235			   const struct list_head *branch_head)1236{1237	struct hns_roce_hem_item *hem, *temp_hem;1238	int total = 0;1239	int offset;1240	u64 step;1241 1242	step = hem_list_calc_ba_range(r->hopnum, 1, unit);1243	if (step < 1)1244		return -EINVAL;1245 1246	/* if exist mid bt, link L1 to L0 */1247	list_for_each_entry_safe(hem, temp_hem, branch_head, list) {1248		offset = (hem->start - r->offset) / step * BA_BYTE_LEN;1249		hem_list_link_bt(cpu_base + offset, hem->dma_addr);1250		total++;1251	}1252 1253	return total;1254}1255 1256static int1257setup_root_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_list *hem_list,1258	       int unit, int max_ba_num, struct hns_roce_hem_head *head,1259	       const struct hns_roce_buf_region *regions, int region_cnt)1260{1261	const struct hns_roce_buf_region *r;1262	struct hns_roce_hem_item *root_hem;1263	void *cpu_base;1264	u64 phy_base;1265	int i, total;1266	int ret;1267 1268	root_hem = list_first_entry(&head->root,1269				    struct hns_roce_hem_item, list);1270	if (!root_hem)1271		return -ENOMEM;1272 1273	total = 0;1274	for (i = 0; i < region_cnt && total < max_ba_num; i++) {1275		r = &regions[i];1276		if (!r->count)1277			continue;1278 1279		/* all regions's mid[x][0] shared the root_bt's trunk */1280		cpu_base = root_hem->addr + total * BA_BYTE_LEN;1281		phy_base = root_hem->dma_addr + total * BA_BYTE_LEN;1282 1283		/* if hopnum is 0 or 1, cut a new fake hem from the root bt1284		 * which's address share to all regions.1285		 */1286		if (hem_list_is_bottom_bt(r->hopnum, 0))1287			ret = alloc_fake_root_bt(hr_dev, cpu_base, phy_base, r,1288						 &head->branch[i], &head->leaf);1289		else1290			ret = setup_middle_bt(hr_dev, cpu_base, unit, r,1291					      &hem_list->mid_bt[i][1]);1292 1293		if (ret < 0)1294			return ret;1295 1296		total += ret;1297	}1298 1299	list_splice(&head->leaf, &hem_list->btm_bt);1300	list_splice(&head->root, &hem_list->root_bt);1301	for (i = 0; i < region_cnt; i++)1302		list_splice(&head->branch[i], &hem_list->mid_bt[i][0]);1303 1304	return 0;1305}1306 1307static int hem_list_alloc_root_bt(struct hns_roce_dev *hr_dev,1308				  struct hns_roce_hem_list *hem_list, int unit,1309				  const struct hns_roce_buf_region *regions,1310				  int region_cnt)1311{1312	struct hns_roce_hem_item *root_hem;1313	struct hns_roce_hem_head head;1314	int max_ba_num;1315	int ret;1316	int i;1317 1318	root_hem = hem_list_search_item(&hem_list->root_bt, regions[0].offset);1319	if (root_hem)1320		return 0;1321 1322	max_ba_num = 0;1323	root_hem = alloc_root_hem(hr_dev, unit, &max_ba_num, regions,1324				  region_cnt);1325	if (IS_ERR(root_hem))1326		return PTR_ERR(root_hem);1327 1328	/* List head for storing all allocated HEM items */1329	INIT_LIST_HEAD(&head.root);1330	INIT_LIST_HEAD(&head.leaf);1331	for (i = 0; i < region_cnt; i++)1332		INIT_LIST_HEAD(&head.branch[i]);1333 1334	hem_list->root_ba = root_hem->dma_addr;1335	list_add(&root_hem->list, &head.root);1336	ret = setup_root_hem(hr_dev, hem_list, unit, max_ba_num, &head, regions,1337			     region_cnt);1338	if (ret) {1339		for (i = 0; i < region_cnt; i++)1340			hem_list_free_all(hr_dev, &head.branch[i], false);1341 1342		hem_list_free_all(hr_dev, &head.root, true);1343	}1344 1345	return ret;1346}1347 1348/* construct the base address table and link them by address hop config */1349int hns_roce_hem_list_request(struct hns_roce_dev *hr_dev,1350			      struct hns_roce_hem_list *hem_list,1351			      const struct hns_roce_buf_region *regions,1352			      int region_cnt, unsigned int bt_pg_shift)1353{1354	const struct hns_roce_buf_region *r;1355	int ofs, end;1356	int unit;1357	int ret;1358	int i;1359 1360	if (region_cnt > HNS_ROCE_MAX_BT_REGION) {1361		dev_err(hr_dev->dev, "invalid region region_cnt %d!\n",1362			region_cnt);1363		return -EINVAL;1364	}1365 1366	unit = (1 << bt_pg_shift) / BA_BYTE_LEN;1367	for (i = 0; i < region_cnt; i++) {1368		r = &regions[i];1369		if (!r->count)1370			continue;1371 1372		end = r->offset + r->count;1373		for (ofs = r->offset; ofs < end; ofs += unit) {1374			ret = hem_list_alloc_mid_bt(hr_dev, r, unit, ofs,1375						    hem_list->mid_bt[i],1376						    &hem_list->btm_bt);1377			if (ret) {1378				dev_err(hr_dev->dev,1379					"alloc hem trunk fail ret = %d!\n", ret);1380				goto err_alloc;1381			}1382		}1383	}1384 1385	ret = hem_list_alloc_root_bt(hr_dev, hem_list, unit, regions,1386				     region_cnt);1387	if (ret)1388		dev_err(hr_dev->dev, "alloc hem root fail ret = %d!\n", ret);1389	else1390		return 0;1391 1392err_alloc:1393	hns_roce_hem_list_release(hr_dev, hem_list);1394 1395	return ret;1396}1397 1398void hns_roce_hem_list_release(struct hns_roce_dev *hr_dev,1399			       struct hns_roce_hem_list *hem_list)1400{1401	int i, j;1402 1403	for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)1404		for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)1405			hem_list_free_all(hr_dev, &hem_list->mid_bt[i][j],1406					  j != 0);1407 1408	hem_list_free_all(hr_dev, &hem_list->root_bt, true);1409	INIT_LIST_HEAD(&hem_list->btm_bt);1410	hem_list->root_ba = 0;1411}1412 1413void hns_roce_hem_list_init(struct hns_roce_hem_list *hem_list)1414{1415	int i, j;1416 1417	INIT_LIST_HEAD(&hem_list->root_bt);1418	INIT_LIST_HEAD(&hem_list->btm_bt);1419	for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)1420		for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)1421			INIT_LIST_HEAD(&hem_list->mid_bt[i][j]);1422}1423 1424void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev,1425				 struct hns_roce_hem_list *hem_list,1426				 int offset, int *mtt_cnt)1427{1428	struct list_head *head = &hem_list->btm_bt;1429	struct hns_roce_hem_item *hem, *temp_hem;1430	void *cpu_base = NULL;1431	int nr = 0;1432 1433	list_for_each_entry_safe(hem, temp_hem, head, sibling) {1434		if (hem_list_page_is_in_range(hem, offset)) {1435			nr = offset - hem->start;1436			cpu_base = hem->addr + nr * BA_BYTE_LEN;1437			nr = hem->end + 1 - offset;1438			break;1439		}1440	}1441 1442	if (mtt_cnt)1443		*mtt_cnt = nr;1444 1445	return cpu_base;1446}1447