19a443537Soulijun /*
29a443537Soulijun * Copyright (c) 2016 Hisilicon Limited.
39a443537Soulijun * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
49a443537Soulijun *
59a443537Soulijun * This software is available to you under a choice of one of two
69a443537Soulijun * licenses. You may choose to be licensed under the terms of the GNU
79a443537Soulijun * General Public License (GPL) Version 2, available from the file
89a443537Soulijun * COPYING in the main directory of this source tree, or the
99a443537Soulijun * OpenIB.org BSD license below:
109a443537Soulijun *
119a443537Soulijun * Redistribution and use in source and binary forms, with or
129a443537Soulijun * without modification, are permitted provided that the following
139a443537Soulijun * conditions are met:
149a443537Soulijun *
159a443537Soulijun * - Redistributions of source code must retain the above
169a443537Soulijun * copyright notice, this list of conditions and the following
179a443537Soulijun * disclaimer.
189a443537Soulijun *
199a443537Soulijun * - Redistributions in binary form must reproduce the above
209a443537Soulijun * copyright notice, this list of conditions and the following
219a443537Soulijun * disclaimer in the documentation and/or other materials
229a443537Soulijun * provided with the distribution.
239a443537Soulijun *
249a443537Soulijun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
259a443537Soulijun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
269a443537Soulijun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
279a443537Soulijun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
289a443537Soulijun * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
299a443537Soulijun * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
309a443537Soulijun * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
319a443537Soulijun * SOFTWARE.
329a443537Soulijun */
339a443537Soulijun
349a443537Soulijun #include "hns_roce_device.h"
359a443537Soulijun #include "hns_roce_hem.h"
369a443537Soulijun #include "hns_roce_common.h"
379a443537Soulijun
382f49de21SXi Wang #define HEM_INDEX_BUF BIT(0)
392f49de21SXi Wang #define HEM_INDEX_L0 BIT(1)
402f49de21SXi Wang #define HEM_INDEX_L1 BIT(2)
412f49de21SXi Wang struct hns_roce_hem_index {
422f49de21SXi Wang u64 buf;
432f49de21SXi Wang u64 l0;
442f49de21SXi Wang u64 l1;
452f49de21SXi Wang u32 inited; /* indicate which index is available */
462f49de21SXi Wang };
472f49de21SXi Wang
hns_roce_check_whether_mhop(struct hns_roce_dev * hr_dev,u32 type)48a25d13cbSShaobo Xu bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type)
49a25d13cbSShaobo Xu {
50d7019c0fSLijun Ou int hop_num = 0;
51a25d13cbSShaobo Xu
52d7019c0fSLijun Ou switch (type) {
53d7019c0fSLijun Ou case HEM_TYPE_QPC:
54d7019c0fSLijun Ou hop_num = hr_dev->caps.qpc_hop_num;
55d7019c0fSLijun Ou break;
56d7019c0fSLijun Ou case HEM_TYPE_MTPT:
57d7019c0fSLijun Ou hop_num = hr_dev->caps.mpt_hop_num;
58d7019c0fSLijun Ou break;
59d7019c0fSLijun Ou case HEM_TYPE_CQC:
60d7019c0fSLijun Ou hop_num = hr_dev->caps.cqc_hop_num;
61d7019c0fSLijun Ou break;
62d7019c0fSLijun Ou case HEM_TYPE_SRQC:
63d7019c0fSLijun Ou hop_num = hr_dev->caps.srqc_hop_num;
64d7019c0fSLijun Ou break;
65d7019c0fSLijun Ou case HEM_TYPE_SCCC:
66d7019c0fSLijun Ou hop_num = hr_dev->caps.sccc_hop_num;
67d7019c0fSLijun Ou break;
68d7019c0fSLijun Ou case HEM_TYPE_QPC_TIMER:
69d7019c0fSLijun Ou hop_num = hr_dev->caps.qpc_timer_hop_num;
70d7019c0fSLijun Ou break;
71d7019c0fSLijun Ou case HEM_TYPE_CQC_TIMER:
72d7019c0fSLijun Ou hop_num = hr_dev->caps.cqc_timer_hop_num;
73d7019c0fSLijun Ou break;
74d6d91e46SWeihang Li case HEM_TYPE_GMV:
75d6d91e46SWeihang Li hop_num = hr_dev->caps.gmv_hop_num;
76d6d91e46SWeihang Li break;
77d7019c0fSLijun Ou default:
78a25d13cbSShaobo Xu return false;
79a25d13cbSShaobo Xu }
80a25d13cbSShaobo Xu
81272bba19SRuan Jinjie return hop_num;
82d7019c0fSLijun Ou }
83d7019c0fSLijun Ou
hns_roce_check_hem_null(struct hns_roce_hem ** hem,u64 hem_idx,u32 bt_chunk_num,u64 hem_max_num)8438dcb350SXi Wang static bool hns_roce_check_hem_null(struct hns_roce_hem **hem, u64 hem_idx,
859bba3f0cSXi Wang u32 bt_chunk_num, u64 hem_max_num)
86a25d13cbSShaobo Xu {
8738dcb350SXi Wang u64 start_idx = round_down(hem_idx, bt_chunk_num);
889bba3f0cSXi Wang u64 check_max_num = start_idx + bt_chunk_num;
899bba3f0cSXi Wang u64 i;
90a25d13cbSShaobo Xu
919bba3f0cSXi Wang for (i = start_idx; (i < check_max_num) && (i < hem_max_num); i++)
9238dcb350SXi Wang if (i != hem_idx && hem[i])
93a25d13cbSShaobo Xu return false;
94a25d13cbSShaobo Xu
95a25d13cbSShaobo Xu return true;
96a25d13cbSShaobo Xu }
97a25d13cbSShaobo Xu
hns_roce_check_bt_null(u64 ** bt,u64 ba_idx,u32 bt_chunk_num)9838dcb350SXi Wang static bool hns_roce_check_bt_null(u64 **bt, u64 ba_idx, u32 bt_chunk_num)
99a25d13cbSShaobo Xu {
10038dcb350SXi Wang u64 start_idx = round_down(ba_idx, bt_chunk_num);
101a25d13cbSShaobo Xu int i;
102a25d13cbSShaobo Xu
103a25d13cbSShaobo Xu for (i = 0; i < bt_chunk_num; i++)
10438dcb350SXi Wang if (i != ba_idx && bt[start_idx + i])
105a25d13cbSShaobo Xu return false;
106a25d13cbSShaobo Xu
107a25d13cbSShaobo Xu return true;
108a25d13cbSShaobo Xu }
109a25d13cbSShaobo Xu
hns_roce_get_bt_num(u32 table_type,u32 hop_num)110a25d13cbSShaobo Xu static int hns_roce_get_bt_num(u32 table_type, u32 hop_num)
111a25d13cbSShaobo Xu {
112a25d13cbSShaobo Xu if (check_whether_bt_num_3(table_type, hop_num))
113a25d13cbSShaobo Xu return 3;
114a25d13cbSShaobo Xu else if (check_whether_bt_num_2(table_type, hop_num))
115a25d13cbSShaobo Xu return 2;
116a25d13cbSShaobo Xu else if (check_whether_bt_num_1(table_type, hop_num))
117a25d13cbSShaobo Xu return 1;
118a25d13cbSShaobo Xu else
119a25d13cbSShaobo Xu return 0;
120a25d13cbSShaobo Xu }
121a25d13cbSShaobo Xu
get_hem_table_config(struct hns_roce_dev * hr_dev,struct hns_roce_hem_mhop * mhop,u32 type)122d7019c0fSLijun Ou static int get_hem_table_config(struct hns_roce_dev *hr_dev,
123d7019c0fSLijun Ou struct hns_roce_hem_mhop *mhop,
124d7019c0fSLijun Ou u32 type)
125a25d13cbSShaobo Xu {
126a25d13cbSShaobo Xu struct device *dev = hr_dev->dev;
127a25d13cbSShaobo Xu
128d7019c0fSLijun Ou switch (type) {
129a25d13cbSShaobo Xu case HEM_TYPE_QPC:
130a25d13cbSShaobo Xu mhop->buf_chunk_size = 1 << (hr_dev->caps.qpc_buf_pg_sz
131a25d13cbSShaobo Xu + PAGE_SHIFT);
132a25d13cbSShaobo Xu mhop->bt_chunk_size = 1 << (hr_dev->caps.qpc_ba_pg_sz
133a25d13cbSShaobo Xu + PAGE_SHIFT);
134a25d13cbSShaobo Xu mhop->ba_l0_num = hr_dev->caps.qpc_bt_num;
135a25d13cbSShaobo Xu mhop->hop_num = hr_dev->caps.qpc_hop_num;
136a25d13cbSShaobo Xu break;
137a25d13cbSShaobo Xu case HEM_TYPE_MTPT:
138a25d13cbSShaobo Xu mhop->buf_chunk_size = 1 << (hr_dev->caps.mpt_buf_pg_sz
139a25d13cbSShaobo Xu + PAGE_SHIFT);
140a25d13cbSShaobo Xu mhop->bt_chunk_size = 1 << (hr_dev->caps.mpt_ba_pg_sz
141a25d13cbSShaobo Xu + PAGE_SHIFT);
142a25d13cbSShaobo Xu mhop->ba_l0_num = hr_dev->caps.mpt_bt_num;
143a25d13cbSShaobo Xu mhop->hop_num = hr_dev->caps.mpt_hop_num;
144a25d13cbSShaobo Xu break;
145a25d13cbSShaobo Xu case HEM_TYPE_CQC:
146a25d13cbSShaobo Xu mhop->buf_chunk_size = 1 << (hr_dev->caps.cqc_buf_pg_sz
147a25d13cbSShaobo Xu + PAGE_SHIFT);
148a25d13cbSShaobo Xu mhop->bt_chunk_size = 1 << (hr_dev->caps.cqc_ba_pg_sz
149a25d13cbSShaobo Xu + PAGE_SHIFT);
150a25d13cbSShaobo Xu mhop->ba_l0_num = hr_dev->caps.cqc_bt_num;
151a25d13cbSShaobo Xu mhop->hop_num = hr_dev->caps.cqc_hop_num;
152a25d13cbSShaobo Xu break;
1536a157f7dSYangyang Li case HEM_TYPE_SCCC:
1546a157f7dSYangyang Li mhop->buf_chunk_size = 1 << (hr_dev->caps.sccc_buf_pg_sz
1556a157f7dSYangyang Li + PAGE_SHIFT);
1566a157f7dSYangyang Li mhop->bt_chunk_size = 1 << (hr_dev->caps.sccc_ba_pg_sz
1576a157f7dSYangyang Li + PAGE_SHIFT);
1586a157f7dSYangyang Li mhop->ba_l0_num = hr_dev->caps.sccc_bt_num;
1596a157f7dSYangyang Li mhop->hop_num = hr_dev->caps.sccc_hop_num;
1606a157f7dSYangyang Li break;
1610e40dc2fSYangyang Li case HEM_TYPE_QPC_TIMER:
1620e40dc2fSYangyang Li mhop->buf_chunk_size = 1 << (hr_dev->caps.qpc_timer_buf_pg_sz
1630e40dc2fSYangyang Li + PAGE_SHIFT);
1640e40dc2fSYangyang Li mhop->bt_chunk_size = 1 << (hr_dev->caps.qpc_timer_ba_pg_sz
1650e40dc2fSYangyang Li + PAGE_SHIFT);
1660e40dc2fSYangyang Li mhop->ba_l0_num = hr_dev->caps.qpc_timer_bt_num;
1670e40dc2fSYangyang Li mhop->hop_num = hr_dev->caps.qpc_timer_hop_num;
1680e40dc2fSYangyang Li break;
1690e40dc2fSYangyang Li case HEM_TYPE_CQC_TIMER:
1700e40dc2fSYangyang Li mhop->buf_chunk_size = 1 << (hr_dev->caps.cqc_timer_buf_pg_sz
1710e40dc2fSYangyang Li + PAGE_SHIFT);
1720e40dc2fSYangyang Li mhop->bt_chunk_size = 1 << (hr_dev->caps.cqc_timer_ba_pg_sz
1730e40dc2fSYangyang Li + PAGE_SHIFT);
1740e40dc2fSYangyang Li mhop->ba_l0_num = hr_dev->caps.cqc_timer_bt_num;
1750e40dc2fSYangyang Li mhop->hop_num = hr_dev->caps.cqc_timer_hop_num;
1760e40dc2fSYangyang Li break;
177a25d13cbSShaobo Xu case HEM_TYPE_SRQC:
178a25d13cbSShaobo Xu mhop->buf_chunk_size = 1 << (hr_dev->caps.srqc_buf_pg_sz
179a25d13cbSShaobo Xu + PAGE_SHIFT);
180a25d13cbSShaobo Xu mhop->bt_chunk_size = 1 << (hr_dev->caps.srqc_ba_pg_sz
181a25d13cbSShaobo Xu + PAGE_SHIFT);
182a25d13cbSShaobo Xu mhop->ba_l0_num = hr_dev->caps.srqc_bt_num;
183a25d13cbSShaobo Xu mhop->hop_num = hr_dev->caps.srqc_hop_num;
184a25d13cbSShaobo Xu break;
185d6d91e46SWeihang Li case HEM_TYPE_GMV:
186d6d91e46SWeihang Li mhop->buf_chunk_size = 1 << (hr_dev->caps.gmv_buf_pg_sz +
187d6d91e46SWeihang Li PAGE_SHIFT);
188d6d91e46SWeihang Li mhop->bt_chunk_size = 1 << (hr_dev->caps.gmv_ba_pg_sz +
189d6d91e46SWeihang Li PAGE_SHIFT);
190d6d91e46SWeihang Li mhop->ba_l0_num = hr_dev->caps.gmv_bt_num;
191d6d91e46SWeihang Li mhop->hop_num = hr_dev->caps.gmv_hop_num;
192d6d91e46SWeihang Li break;
193a25d13cbSShaobo Xu default:
19461918e9bSYixing Liu dev_err(dev, "table %u not support multi-hop addressing!\n",
195d7019c0fSLijun Ou type);
196a25d13cbSShaobo Xu return -EINVAL;
197a25d13cbSShaobo Xu }
198a25d13cbSShaobo Xu
199d7019c0fSLijun Ou return 0;
200d7019c0fSLijun Ou }
201d7019c0fSLijun Ou
hns_roce_calc_hem_mhop(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long * obj,struct hns_roce_hem_mhop * mhop)202d7019c0fSLijun Ou int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev,
203d7019c0fSLijun Ou struct hns_roce_hem_table *table, unsigned long *obj,
204d7019c0fSLijun Ou struct hns_roce_hem_mhop *mhop)
205d7019c0fSLijun Ou {
206d7019c0fSLijun Ou struct device *dev = hr_dev->dev;
207d7019c0fSLijun Ou u32 chunk_ba_num;
208dc93a0d9SLang Cheng u32 chunk_size;
209d7019c0fSLijun Ou u32 table_idx;
210d7019c0fSLijun Ou u32 bt_num;
211d7019c0fSLijun Ou
212d7019c0fSLijun Ou if (get_hem_table_config(hr_dev, mhop, table->type))
213d7019c0fSLijun Ou return -EINVAL;
214d7019c0fSLijun Ou
215a25d13cbSShaobo Xu if (!obj)
216a25d13cbSShaobo Xu return 0;
217a25d13cbSShaobo Xu
2186a93c77aSShaobo Xu /*
2196a157f7dSYangyang Li * QPC/MTPT/CQC/SRQC/SCCC alloc hem for buffer pages.
2206a93c77aSShaobo Xu * MTT/CQE alloc hem for bt pages.
2216a93c77aSShaobo Xu */
222a25d13cbSShaobo Xu bt_num = hns_roce_get_bt_num(table->type, mhop->hop_num);
2232a3d923fSLijun Ou chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;
2246a93c77aSShaobo Xu chunk_size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size :
2256a93c77aSShaobo Xu mhop->bt_chunk_size;
22661b460d1SXi Wang table_idx = *obj / (chunk_size / table->obj_size);
227a25d13cbSShaobo Xu switch (bt_num) {
228a25d13cbSShaobo Xu case 3:
229a25d13cbSShaobo Xu mhop->l2_idx = table_idx & (chunk_ba_num - 1);
230a25d13cbSShaobo Xu mhop->l1_idx = table_idx / chunk_ba_num & (chunk_ba_num - 1);
23173b4e1f4SLijun Ou mhop->l0_idx = (table_idx / chunk_ba_num) / chunk_ba_num;
232a25d13cbSShaobo Xu break;
233a25d13cbSShaobo Xu case 2:
234a25d13cbSShaobo Xu mhop->l1_idx = table_idx & (chunk_ba_num - 1);
235a25d13cbSShaobo Xu mhop->l0_idx = table_idx / chunk_ba_num;
236a25d13cbSShaobo Xu break;
237a25d13cbSShaobo Xu case 1:
238a25d13cbSShaobo Xu mhop->l0_idx = table_idx;
239a25d13cbSShaobo Xu break;
240a25d13cbSShaobo Xu default:
24161918e9bSYixing Liu dev_err(dev, "table %u not support hop_num = %u!\n",
242a25d13cbSShaobo Xu table->type, mhop->hop_num);
243a25d13cbSShaobo Xu return -EINVAL;
244a25d13cbSShaobo Xu }
245a25d13cbSShaobo Xu if (mhop->l0_idx >= mhop->ba_l0_num)
246a25d13cbSShaobo Xu mhop->l0_idx %= mhop->ba_l0_num;
247a25d13cbSShaobo Xu
248a25d13cbSShaobo Xu return 0;
249a25d13cbSShaobo Xu }
250a25d13cbSShaobo Xu
hns_roce_alloc_hem(struct hns_roce_dev * hr_dev,unsigned long hem_alloc_size,gfp_t gfp_mask)251a25d13cbSShaobo Xu static struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev,
252a25d13cbSShaobo Xu unsigned long hem_alloc_size,
2539a443537Soulijun gfp_t gfp_mask)
2549a443537Soulijun {
2559a443537Soulijun struct hns_roce_hem *hem;
2569a443537Soulijun int order;
2579a443537Soulijun void *buf;
2589a443537Soulijun
2599a443537Soulijun WARN_ON(gfp_mask & __GFP_HIGHMEM);
2609a443537Soulijun
261c00743cbSYunsheng Lin order = get_order(hem_alloc_size);
262c00743cbSYunsheng Lin if (PAGE_SIZE << order != hem_alloc_size) {
263c00743cbSYunsheng Lin dev_err(hr_dev->dev, "invalid hem_alloc_size: %lu!\n",
264c00743cbSYunsheng Lin hem_alloc_size);
265c00743cbSYunsheng Lin return NULL;
266c00743cbSYunsheng Lin }
267c00743cbSYunsheng Lin
2689a443537Soulijun hem = kmalloc(sizeof(*hem),
2699a443537Soulijun gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
2709a443537Soulijun if (!hem)
2719a443537Soulijun return NULL;
2729a443537Soulijun
273c00743cbSYunsheng Lin buf = dma_alloc_coherent(hr_dev->dev, hem_alloc_size,
274c00743cbSYunsheng Lin &hem->dma, gfp_mask);
2759a443537Soulijun if (!buf)
2769a443537Soulijun goto fail;
2779a443537Soulijun
278c00743cbSYunsheng Lin hem->buf = buf;
279c00743cbSYunsheng Lin hem->size = hem_alloc_size;
2809a443537Soulijun
2819a443537Soulijun return hem;
2829a443537Soulijun
2839a443537Soulijun fail:
284dc3bda6eSwenglianfa kfree(hem);
2859a443537Soulijun return NULL;
2869a443537Soulijun }
2879a443537Soulijun
hns_roce_free_hem(struct hns_roce_dev * hr_dev,struct hns_roce_hem * hem)2889a443537Soulijun void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem)
2899a443537Soulijun {
2909a443537Soulijun if (!hem)
2919a443537Soulijun return;
2929a443537Soulijun
293c00743cbSYunsheng Lin dma_free_coherent(hr_dev->dev, hem->size, hem->buf, hem->dma);
2949a443537Soulijun
2959a443537Soulijun kfree(hem);
2969a443537Soulijun }
2979a443537Soulijun
calc_hem_config(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj,struct hns_roce_hem_mhop * mhop,struct hns_roce_hem_index * index)2982f49de21SXi Wang static int calc_hem_config(struct hns_roce_dev *hr_dev,
2992f49de21SXi Wang struct hns_roce_hem_table *table, unsigned long obj,
3002f49de21SXi Wang struct hns_roce_hem_mhop *mhop,
3012f49de21SXi Wang struct hns_roce_hem_index *index)
302a25d13cbSShaobo Xu {
3032f49de21SXi Wang struct ib_device *ibdev = &hr_dev->ib_dev;
304a25d13cbSShaobo Xu unsigned long mhop_obj = obj;
3052f49de21SXi Wang u32 l0_idx, l1_idx, l2_idx;
3062f49de21SXi Wang u32 chunk_ba_num;
3072f49de21SXi Wang u32 bt_num;
308a25d13cbSShaobo Xu int ret;
309a25d13cbSShaobo Xu
3102f49de21SXi Wang ret = hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, mhop);
311a25d13cbSShaobo Xu if (ret)
312a25d13cbSShaobo Xu return ret;
313a25d13cbSShaobo Xu
3142f49de21SXi Wang l0_idx = mhop->l0_idx;
3152f49de21SXi Wang l1_idx = mhop->l1_idx;
3162f49de21SXi Wang l2_idx = mhop->l2_idx;
3172f49de21SXi Wang chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;
3182f49de21SXi Wang bt_num = hns_roce_get_bt_num(table->type, mhop->hop_num);
319a25d13cbSShaobo Xu switch (bt_num) {
320a25d13cbSShaobo Xu case 3:
3212f49de21SXi Wang index->l1 = l0_idx * chunk_ba_num + l1_idx;
3222f49de21SXi Wang index->l0 = l0_idx;
3232f49de21SXi Wang index->buf = l0_idx * chunk_ba_num * chunk_ba_num +
3242f49de21SXi Wang l1_idx * chunk_ba_num + l2_idx;
325a25d13cbSShaobo Xu break;
326a25d13cbSShaobo Xu case 2:
3272f49de21SXi Wang index->l0 = l0_idx;
3282f49de21SXi Wang index->buf = l0_idx * chunk_ba_num + l1_idx;
329a25d13cbSShaobo Xu break;
330a25d13cbSShaobo Xu case 1:
3312f49de21SXi Wang index->buf = l0_idx;
332a25d13cbSShaobo Xu break;
333a25d13cbSShaobo Xu default:
33461918e9bSYixing Liu ibdev_err(ibdev, "table %u not support mhop.hop_num = %u!\n",
3352f49de21SXi Wang table->type, mhop->hop_num);
336a25d13cbSShaobo Xu return -EINVAL;
337a25d13cbSShaobo Xu }
338a25d13cbSShaobo Xu
3392f49de21SXi Wang if (unlikely(index->buf >= table->num_hem)) {
34061918e9bSYixing Liu ibdev_err(ibdev, "table %u exceed hem limt idx %llu, max %lu!\n",
3412f49de21SXi Wang table->type, index->buf, table->num_hem);
3429bba3f0cSXi Wang return -EINVAL;
3439bba3f0cSXi Wang }
3449bba3f0cSXi Wang
3452f49de21SXi Wang return 0;
346a25d13cbSShaobo Xu }
347a25d13cbSShaobo Xu
free_mhop_hem(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,struct hns_roce_hem_mhop * mhop,struct hns_roce_hem_index * index)3482f49de21SXi Wang static void free_mhop_hem(struct hns_roce_dev *hr_dev,
3492f49de21SXi Wang struct hns_roce_hem_table *table,
3502f49de21SXi Wang struct hns_roce_hem_mhop *mhop,
3512f49de21SXi Wang struct hns_roce_hem_index *index)
3522f49de21SXi Wang {
3532f49de21SXi Wang u32 bt_size = mhop->bt_chunk_size;
3542f49de21SXi Wang struct device *dev = hr_dev->dev;
3552f49de21SXi Wang
3562f49de21SXi Wang if (index->inited & HEM_INDEX_BUF) {
3572f49de21SXi Wang hns_roce_free_hem(hr_dev, table->hem[index->buf]);
3582f49de21SXi Wang table->hem[index->buf] = NULL;
3592f49de21SXi Wang }
3602f49de21SXi Wang
3612f49de21SXi Wang if (index->inited & HEM_INDEX_L1) {
3622f49de21SXi Wang dma_free_coherent(dev, bt_size, table->bt_l1[index->l1],
3632f49de21SXi Wang table->bt_l1_dma_addr[index->l1]);
3642f49de21SXi Wang table->bt_l1[index->l1] = NULL;
3652f49de21SXi Wang }
3662f49de21SXi Wang
3672f49de21SXi Wang if (index->inited & HEM_INDEX_L0) {
3682f49de21SXi Wang dma_free_coherent(dev, bt_size, table->bt_l0[index->l0],
3692f49de21SXi Wang table->bt_l0_dma_addr[index->l0]);
3702f49de21SXi Wang table->bt_l0[index->l0] = NULL;
3712f49de21SXi Wang }
3722f49de21SXi Wang }
3732f49de21SXi Wang
alloc_mhop_hem(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,struct hns_roce_hem_mhop * mhop,struct hns_roce_hem_index * index)3742f49de21SXi Wang static int alloc_mhop_hem(struct hns_roce_dev *hr_dev,
3752f49de21SXi Wang struct hns_roce_hem_table *table,
3762f49de21SXi Wang struct hns_roce_hem_mhop *mhop,
3772f49de21SXi Wang struct hns_roce_hem_index *index)
3782f49de21SXi Wang {
3792f49de21SXi Wang u32 bt_size = mhop->bt_chunk_size;
3802f49de21SXi Wang struct device *dev = hr_dev->dev;
3812f49de21SXi Wang gfp_t flag;
3822f49de21SXi Wang u64 bt_ba;
3832f49de21SXi Wang u32 size;
3842f49de21SXi Wang int ret;
3852f49de21SXi Wang
386a25d13cbSShaobo Xu /* alloc L1 BA's chunk */
3872f49de21SXi Wang if ((check_whether_bt_num_3(table->type, mhop->hop_num) ||
3882f49de21SXi Wang check_whether_bt_num_2(table->type, mhop->hop_num)) &&
3892f49de21SXi Wang !table->bt_l0[index->l0]) {
3902f49de21SXi Wang table->bt_l0[index->l0] = dma_alloc_coherent(dev, bt_size,
3912f49de21SXi Wang &table->bt_l0_dma_addr[index->l0],
392a25d13cbSShaobo Xu GFP_KERNEL);
3932f49de21SXi Wang if (!table->bt_l0[index->l0]) {
394a25d13cbSShaobo Xu ret = -ENOMEM;
395a25d13cbSShaobo Xu goto out;
396a25d13cbSShaobo Xu }
3972f49de21SXi Wang index->inited |= HEM_INDEX_L0;
398a25d13cbSShaobo Xu }
399a25d13cbSShaobo Xu
400a25d13cbSShaobo Xu /* alloc L2 BA's chunk */
4012f49de21SXi Wang if (check_whether_bt_num_3(table->type, mhop->hop_num) &&
4022f49de21SXi Wang !table->bt_l1[index->l1]) {
4032f49de21SXi Wang table->bt_l1[index->l1] = dma_alloc_coherent(dev, bt_size,
4042f49de21SXi Wang &table->bt_l1_dma_addr[index->l1],
405a25d13cbSShaobo Xu GFP_KERNEL);
4062f49de21SXi Wang if (!table->bt_l1[index->l1]) {
407a25d13cbSShaobo Xu ret = -ENOMEM;
4082f49de21SXi Wang goto err_alloc_hem;
409a25d13cbSShaobo Xu }
4102f49de21SXi Wang index->inited |= HEM_INDEX_L1;
4112f49de21SXi Wang *(table->bt_l0[index->l0] + mhop->l1_idx) =
4122f49de21SXi Wang table->bt_l1_dma_addr[index->l1];
413a25d13cbSShaobo Xu }
414a25d13cbSShaobo Xu
4156a93c77aSShaobo Xu /*
4166a157f7dSYangyang Li * alloc buffer space chunk for QPC/MTPT/CQC/SRQC/SCCC.
4176a93c77aSShaobo Xu * alloc bt space chunk for MTT/CQE.
4186a93c77aSShaobo Xu */
4192f49de21SXi Wang size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size : bt_size;
42029dc0635SYunsheng Lin flag = GFP_KERNEL | __GFP_NOWARN;
421c00743cbSYunsheng Lin table->hem[index->buf] = hns_roce_alloc_hem(hr_dev, size, flag);
4222f49de21SXi Wang if (!table->hem[index->buf]) {
423a25d13cbSShaobo Xu ret = -ENOMEM;
4242f49de21SXi Wang goto err_alloc_hem;
425a25d13cbSShaobo Xu }
426a25d13cbSShaobo Xu
4272f49de21SXi Wang index->inited |= HEM_INDEX_BUF;
428c00743cbSYunsheng Lin bt_ba = table->hem[index->buf]->dma;
429c00743cbSYunsheng Lin
430a25d13cbSShaobo Xu if (table->type < HEM_TYPE_MTT) {
4312f49de21SXi Wang if (mhop->hop_num == 2)
4322f49de21SXi Wang *(table->bt_l1[index->l1] + mhop->l2_idx) = bt_ba;
4332f49de21SXi Wang else if (mhop->hop_num == 1)
4342f49de21SXi Wang *(table->bt_l0[index->l0] + mhop->l1_idx) = bt_ba;
4352f49de21SXi Wang } else if (mhop->hop_num == 2) {
4362f49de21SXi Wang *(table->bt_l0[index->l0] + mhop->l1_idx) = bt_ba;
4372f49de21SXi Wang }
4382f49de21SXi Wang
4392f49de21SXi Wang return 0;
4402f49de21SXi Wang err_alloc_hem:
4412f49de21SXi Wang free_mhop_hem(hr_dev, table, mhop, index);
4422f49de21SXi Wang out:
4432f49de21SXi Wang return ret;
4442f49de21SXi Wang }
4452f49de21SXi Wang
set_mhop_hem(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj,struct hns_roce_hem_mhop * mhop,struct hns_roce_hem_index * index)4462f49de21SXi Wang static int set_mhop_hem(struct hns_roce_dev *hr_dev,
4472f49de21SXi Wang struct hns_roce_hem_table *table, unsigned long obj,
4482f49de21SXi Wang struct hns_roce_hem_mhop *mhop,
4492f49de21SXi Wang struct hns_roce_hem_index *index)
4502f49de21SXi Wang {
4512f49de21SXi Wang struct ib_device *ibdev = &hr_dev->ib_dev;
452e50cda2bSWenpeng Liang u32 step_idx;
453d35dc58dSGustavo A. R. Silva int ret = 0;
4542f49de21SXi Wang
4552f49de21SXi Wang if (index->inited & HEM_INDEX_L0) {
4562f49de21SXi Wang ret = hr_dev->hw->set_hem(hr_dev, table, obj, 0);
4572f49de21SXi Wang if (ret) {
4582f49de21SXi Wang ibdev_err(ibdev, "set HEM step 0 failed!\n");
4592f49de21SXi Wang goto out;
4602f49de21SXi Wang }
4612f49de21SXi Wang }
4622f49de21SXi Wang
4632f49de21SXi Wang if (index->inited & HEM_INDEX_L1) {
4642f49de21SXi Wang ret = hr_dev->hw->set_hem(hr_dev, table, obj, 1);
4652f49de21SXi Wang if (ret) {
4662f49de21SXi Wang ibdev_err(ibdev, "set HEM step 1 failed!\n");
4672f49de21SXi Wang goto out;
4682f49de21SXi Wang }
4692f49de21SXi Wang }
4702f49de21SXi Wang
4712f49de21SXi Wang if (index->inited & HEM_INDEX_BUF) {
4722f49de21SXi Wang if (mhop->hop_num == HNS_ROCE_HOP_NUM_0)
473a25d13cbSShaobo Xu step_idx = 0;
4742f49de21SXi Wang else
4752f49de21SXi Wang step_idx = mhop->hop_num;
4762f49de21SXi Wang ret = hr_dev->hw->set_hem(hr_dev, table, obj, step_idx);
4772f49de21SXi Wang if (ret)
4782f49de21SXi Wang ibdev_err(ibdev, "set HEM step last failed!\n");
4792f49de21SXi Wang }
4802f49de21SXi Wang out:
4812f49de21SXi Wang return ret;
4822f49de21SXi Wang }
4832f49de21SXi Wang
hns_roce_table_mhop_get(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj)4842f49de21SXi Wang static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev,
4852f49de21SXi Wang struct hns_roce_hem_table *table,
4862f49de21SXi Wang unsigned long obj)
4872f49de21SXi Wang {
4882f49de21SXi Wang struct ib_device *ibdev = &hr_dev->ib_dev;
4892f49de21SXi Wang struct hns_roce_hem_index index = {};
4902f49de21SXi Wang struct hns_roce_hem_mhop mhop = {};
4912f49de21SXi Wang int ret;
4922f49de21SXi Wang
4932f49de21SXi Wang ret = calc_hem_config(hr_dev, table, obj, &mhop, &index);
4942f49de21SXi Wang if (ret) {
4952f49de21SXi Wang ibdev_err(ibdev, "calc hem config failed!\n");
4962f49de21SXi Wang return ret;
4972f49de21SXi Wang }
4982f49de21SXi Wang
4992f49de21SXi Wang mutex_lock(&table->mutex);
5002f49de21SXi Wang if (table->hem[index.buf]) {
50182eb481dSWeihang Li refcount_inc(&table->hem[index.buf]->refcount);
5022f49de21SXi Wang goto out;
5032f49de21SXi Wang }
5042f49de21SXi Wang
5052f49de21SXi Wang ret = alloc_mhop_hem(hr_dev, table, &mhop, &index);
5062f49de21SXi Wang if (ret) {
5072f49de21SXi Wang ibdev_err(ibdev, "alloc mhop hem failed!\n");
5082f49de21SXi Wang goto out;
509a25d13cbSShaobo Xu }
510a25d13cbSShaobo Xu
511a25d13cbSShaobo Xu /* set HEM base address to hardware */
5122f49de21SXi Wang if (table->type < HEM_TYPE_MTT) {
5132f49de21SXi Wang ret = set_mhop_hem(hr_dev, table, obj, &mhop, &index);
5142f49de21SXi Wang if (ret) {
5152f49de21SXi Wang ibdev_err(ibdev, "set HEM address to HW failed!\n");
5162f49de21SXi Wang goto err_alloc;
517a25d13cbSShaobo Xu }
518a25d13cbSShaobo Xu }
519a25d13cbSShaobo Xu
52082eb481dSWeihang Li refcount_set(&table->hem[index.buf]->refcount, 1);
521a25d13cbSShaobo Xu goto out;
522a25d13cbSShaobo Xu
5232f49de21SXi Wang err_alloc:
5242f49de21SXi Wang free_mhop_hem(hr_dev, table, &mhop, &index);
525a25d13cbSShaobo Xu out:
526a25d13cbSShaobo Xu mutex_unlock(&table->mutex);
527a25d13cbSShaobo Xu return ret;
528a25d13cbSShaobo Xu }
529a25d13cbSShaobo Xu
hns_roce_table_get(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj)5309a443537Soulijun int hns_roce_table_get(struct hns_roce_dev *hr_dev,
5319a443537Soulijun struct hns_roce_hem_table *table, unsigned long obj)
5329a443537Soulijun {
53313ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev;
5349a443537Soulijun unsigned long i;
535dc93a0d9SLang Cheng int ret = 0;
5369a443537Soulijun
537a25d13cbSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type))
538a25d13cbSShaobo Xu return hns_roce_table_mhop_get(hr_dev, table, obj);
539a25d13cbSShaobo Xu
54061b460d1SXi Wang i = obj / (table->table_chunk_size / table->obj_size);
5419a443537Soulijun
5429a443537Soulijun mutex_lock(&table->mutex);
5439a443537Soulijun
5449a443537Soulijun if (table->hem[i]) {
54582eb481dSWeihang Li refcount_inc(&table->hem[i]->refcount);
5469a443537Soulijun goto out;
5479a443537Soulijun }
5489a443537Soulijun
5499a443537Soulijun table->hem[i] = hns_roce_alloc_hem(hr_dev,
55029a1fe5dSWei Hu(Xavier) table->table_chunk_size,
55129dc0635SYunsheng Lin GFP_KERNEL | __GFP_NOWARN);
5529a443537Soulijun if (!table->hem[i]) {
5539a443537Soulijun ret = -ENOMEM;
5549a443537Soulijun goto out;
5559a443537Soulijun }
5569a443537Soulijun
5579a443537Soulijun /* Set HEM base address(128K/page, pa) to Hardware */
558cf5b608fSChengchang Tang ret = hr_dev->hw->set_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT);
559cf5b608fSChengchang Tang if (ret) {
56008eb3018SWei Hu(Xavier) hns_roce_free_hem(hr_dev, table->hem[i]);
56108eb3018SWei Hu(Xavier) table->hem[i] = NULL;
562cf5b608fSChengchang Tang dev_err(dev, "set HEM base address to HW failed, ret = %d.\n",
563cf5b608fSChengchang Tang ret);
5649a443537Soulijun goto out;
5659a443537Soulijun }
5669a443537Soulijun
56782eb481dSWeihang Li refcount_set(&table->hem[i]->refcount, 1);
5689a443537Soulijun out:
5699a443537Soulijun mutex_unlock(&table->mutex);
5709a443537Soulijun return ret;
5719a443537Soulijun }
5729a443537Soulijun
clear_mhop_hem(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj,struct hns_roce_hem_mhop * mhop,struct hns_roce_hem_index * index)57338dcb350SXi Wang static void clear_mhop_hem(struct hns_roce_dev *hr_dev,
57438dcb350SXi Wang struct hns_roce_hem_table *table, unsigned long obj,
57538dcb350SXi Wang struct hns_roce_hem_mhop *mhop,
57638dcb350SXi Wang struct hns_roce_hem_index *index)
57738dcb350SXi Wang {
57838dcb350SXi Wang struct ib_device *ibdev = &hr_dev->ib_dev;
57938dcb350SXi Wang u32 hop_num = mhop->hop_num;
58038dcb350SXi Wang u32 chunk_ba_num;
581e50cda2bSWenpeng Liang u32 step_idx;
582a519a612SChengchang Tang int ret;
58338dcb350SXi Wang
58438dcb350SXi Wang index->inited = HEM_INDEX_BUF;
58538dcb350SXi Wang chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN;
58638dcb350SXi Wang if (check_whether_bt_num_2(table->type, hop_num)) {
58738dcb350SXi Wang if (hns_roce_check_hem_null(table->hem, index->buf,
58838dcb350SXi Wang chunk_ba_num, table->num_hem))
58938dcb350SXi Wang index->inited |= HEM_INDEX_L0;
59038dcb350SXi Wang } else if (check_whether_bt_num_3(table->type, hop_num)) {
59138dcb350SXi Wang if (hns_roce_check_hem_null(table->hem, index->buf,
59238dcb350SXi Wang chunk_ba_num, table->num_hem)) {
59338dcb350SXi Wang index->inited |= HEM_INDEX_L1;
59438dcb350SXi Wang if (hns_roce_check_bt_null(table->bt_l1, index->l1,
59538dcb350SXi Wang chunk_ba_num))
59638dcb350SXi Wang index->inited |= HEM_INDEX_L0;
59738dcb350SXi Wang }
59838dcb350SXi Wang }
59938dcb350SXi Wang
60038dcb350SXi Wang if (table->type < HEM_TYPE_MTT) {
60138dcb350SXi Wang if (hop_num == HNS_ROCE_HOP_NUM_0)
60238dcb350SXi Wang step_idx = 0;
60338dcb350SXi Wang else
60438dcb350SXi Wang step_idx = hop_num;
60538dcb350SXi Wang
606a519a612SChengchang Tang ret = hr_dev->hw->clear_hem(hr_dev, table, obj, step_idx);
607a519a612SChengchang Tang if (ret)
608a519a612SChengchang Tang ibdev_warn(ibdev, "failed to clear hop%u HEM, ret = %d.\n",
609a519a612SChengchang Tang hop_num, ret);
61038dcb350SXi Wang
611a519a612SChengchang Tang if (index->inited & HEM_INDEX_L1) {
612a519a612SChengchang Tang ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 1);
613a519a612SChengchang Tang if (ret)
614a519a612SChengchang Tang ibdev_warn(ibdev, "failed to clear HEM step 1, ret = %d.\n",
615a519a612SChengchang Tang ret);
616a519a612SChengchang Tang }
61738dcb350SXi Wang
618a519a612SChengchang Tang if (index->inited & HEM_INDEX_L0) {
619a519a612SChengchang Tang ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0);
620a519a612SChengchang Tang if (ret)
621a519a612SChengchang Tang ibdev_warn(ibdev, "failed to clear HEM step 0, ret = %d.\n",
622a519a612SChengchang Tang ret);
623a519a612SChengchang Tang }
62438dcb350SXi Wang }
62538dcb350SXi Wang }
62638dcb350SXi Wang
hns_roce_table_mhop_put(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj,int check_refcount)627281d0ccfSColin Ian King static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev,
628a25d13cbSShaobo Xu struct hns_roce_hem_table *table,
629a25d13cbSShaobo Xu unsigned long obj,
630a25d13cbSShaobo Xu int check_refcount)
631a25d13cbSShaobo Xu {
63238dcb350SXi Wang struct ib_device *ibdev = &hr_dev->ib_dev;
63338dcb350SXi Wang struct hns_roce_hem_index index = {};
63438dcb350SXi Wang struct hns_roce_hem_mhop mhop = {};
635a25d13cbSShaobo Xu int ret;
636a25d13cbSShaobo Xu
63738dcb350SXi Wang ret = calc_hem_config(hr_dev, table, obj, &mhop, &index);
63838dcb350SXi Wang if (ret) {
63938dcb350SXi Wang ibdev_err(ibdev, "calc hem config failed!\n");
640a25d13cbSShaobo Xu return;
641a25d13cbSShaobo Xu }
642a25d13cbSShaobo Xu
64382eb481dSWeihang Li if (!check_refcount)
644a25d13cbSShaobo Xu mutex_lock(&table->mutex);
64582eb481dSWeihang Li else if (!refcount_dec_and_mutex_lock(&table->hem[index.buf]->refcount,
64682eb481dSWeihang Li &table->mutex))
647a25d13cbSShaobo Xu return;
648a25d13cbSShaobo Xu
64938dcb350SXi Wang clear_mhop_hem(hr_dev, table, obj, &mhop, &index);
65038dcb350SXi Wang free_mhop_hem(hr_dev, table, &mhop, &index);
651a25d13cbSShaobo Xu
652a25d13cbSShaobo Xu mutex_unlock(&table->mutex);
653a25d13cbSShaobo Xu }
654a25d13cbSShaobo Xu
hns_roce_table_put(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj)6559a443537Soulijun void hns_roce_table_put(struct hns_roce_dev *hr_dev,
6569a443537Soulijun struct hns_roce_hem_table *table, unsigned long obj)
6579a443537Soulijun {
65813ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev;
6599a443537Soulijun unsigned long i;
660a519a612SChengchang Tang int ret;
6619a443537Soulijun
662a25d13cbSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) {
663a25d13cbSShaobo Xu hns_roce_table_mhop_put(hr_dev, table, obj, 1);
664a25d13cbSShaobo Xu return;
665a25d13cbSShaobo Xu }
666a25d13cbSShaobo Xu
66761b460d1SXi Wang i = obj / (table->table_chunk_size / table->obj_size);
6689a443537Soulijun
66982eb481dSWeihang Li if (!refcount_dec_and_mutex_lock(&table->hem[i]->refcount,
67082eb481dSWeihang Li &table->mutex))
67182eb481dSWeihang Li return;
6729a443537Soulijun
673a519a612SChengchang Tang ret = hr_dev->hw->clear_hem(hr_dev, table, obj, HEM_HOP_STEP_DIRECT);
674a519a612SChengchang Tang if (ret)
675a519a612SChengchang Tang dev_warn(dev, "failed to clear HEM base address, ret = %d.\n",
676a519a612SChengchang Tang ret);
6779a443537Soulijun
6789a443537Soulijun hns_roce_free_hem(hr_dev, table->hem[i]);
6799a443537Soulijun table->hem[i] = NULL;
6809a443537Soulijun
6819a443537Soulijun mutex_unlock(&table->mutex);
6829a443537Soulijun }
6839a443537Soulijun
hns_roce_table_find(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,unsigned long obj,dma_addr_t * dma_handle)6846a93c77aSShaobo Xu void *hns_roce_table_find(struct hns_roce_dev *hr_dev,
6856a93c77aSShaobo Xu struct hns_roce_hem_table *table,
6866a93c77aSShaobo Xu unsigned long obj, dma_addr_t *dma_handle)
6879a443537Soulijun {
6886a93c77aSShaobo Xu struct hns_roce_hem_mhop mhop;
6899a443537Soulijun struct hns_roce_hem *hem;
6906a93c77aSShaobo Xu unsigned long mhop_obj = obj;
6910203b14cSoulijun unsigned long obj_per_chunk;
6920203b14cSoulijun unsigned long idx_offset;
6936a93c77aSShaobo Xu int offset, dma_offset;
694dc93a0d9SLang Cheng void *addr = NULL;
695dc93a0d9SLang Cheng u32 hem_idx = 0;
6966a93c77aSShaobo Xu int i, j;
6979a443537Soulijun
6989a443537Soulijun mutex_lock(&table->mutex);
6996a93c77aSShaobo Xu
7006a93c77aSShaobo Xu if (!hns_roce_check_whether_mhop(hr_dev, table->type)) {
7010203b14cSoulijun obj_per_chunk = table->table_chunk_size / table->obj_size;
70261b460d1SXi Wang hem = table->hem[obj / obj_per_chunk];
70361b460d1SXi Wang idx_offset = obj % obj_per_chunk;
7040203b14cSoulijun dma_offset = offset = idx_offset * table->obj_size;
7056a93c77aSShaobo Xu } else {
7064772e03dSLijun Ou u32 seg_size = 64; /* 8 bytes per BA and 8 BA per segment */
7074772e03dSLijun Ou
7080e20ebf8SLang Cheng if (hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, &mhop))
7090e20ebf8SLang Cheng goto out;
7106a93c77aSShaobo Xu /* mtt mhop */
7116a93c77aSShaobo Xu i = mhop.l0_idx;
7126a93c77aSShaobo Xu j = mhop.l1_idx;
7136a93c77aSShaobo Xu if (mhop.hop_num == 2)
7142a3d923fSLijun Ou hem_idx = i * (mhop.bt_chunk_size / BA_BYTE_LEN) + j;
7156a93c77aSShaobo Xu else if (mhop.hop_num == 1 ||
7166a93c77aSShaobo Xu mhop.hop_num == HNS_ROCE_HOP_NUM_0)
7176a93c77aSShaobo Xu hem_idx = i;
7186a93c77aSShaobo Xu
7196a93c77aSShaobo Xu hem = table->hem[hem_idx];
72061b460d1SXi Wang dma_offset = offset = obj * seg_size % mhop.bt_chunk_size;
7216a93c77aSShaobo Xu if (mhop.hop_num == 2)
7226a93c77aSShaobo Xu dma_offset = offset = 0;
7236a93c77aSShaobo Xu }
7249a443537Soulijun
7259a443537Soulijun if (!hem)
7269a443537Soulijun goto out;
7279a443537Soulijun
728c00743cbSYunsheng Lin *dma_handle = hem->dma + dma_offset;
729c00743cbSYunsheng Lin addr = hem->buf + offset;
7309a443537Soulijun
7319a443537Soulijun out:
7329a443537Soulijun mutex_unlock(&table->mutex);
733378efe79SWei Hu\(Xavier\) return addr;
7349a443537Soulijun }
7359a443537Soulijun
hns_roce_init_hem_table(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table,u32 type,unsigned long obj_size,unsigned long nobj)7369a443537Soulijun int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev,
7379a443537Soulijun struct hns_roce_hem_table *table, u32 type,
73829dc0635SYunsheng Lin unsigned long obj_size, unsigned long nobj)
7399a443537Soulijun {
7409a443537Soulijun unsigned long obj_per_chunk;
7419a443537Soulijun unsigned long num_hem;
7429a443537Soulijun
743a25d13cbSShaobo Xu if (!hns_roce_check_whether_mhop(hr_dev, type)) {
74429a1fe5dSWei Hu(Xavier) table->table_chunk_size = hr_dev->caps.chunk_sz;
74529a1fe5dSWei Hu(Xavier) obj_per_chunk = table->table_chunk_size / obj_size;
74661b460d1SXi Wang num_hem = DIV_ROUND_UP(nobj, obj_per_chunk);
7479a443537Soulijun
7489a443537Soulijun table->hem = kcalloc(num_hem, sizeof(*table->hem), GFP_KERNEL);
7499a443537Soulijun if (!table->hem)
7509a443537Soulijun return -ENOMEM;
751a25d13cbSShaobo Xu } else {
752d7019c0fSLijun Ou struct hns_roce_hem_mhop mhop = {};
753a25d13cbSShaobo Xu unsigned long buf_chunk_size;
754a25d13cbSShaobo Xu unsigned long bt_chunk_size;
755a25d13cbSShaobo Xu unsigned long bt_chunk_num;
75662f3b70eSXinhao Liu unsigned long num_bt_l0;
757a25d13cbSShaobo Xu u32 hop_num;
758a25d13cbSShaobo Xu
759d7019c0fSLijun Ou if (get_hem_table_config(hr_dev, &mhop, type))
760a25d13cbSShaobo Xu return -EINVAL;
761d7019c0fSLijun Ou
762d7019c0fSLijun Ou buf_chunk_size = mhop.buf_chunk_size;
763d7019c0fSLijun Ou bt_chunk_size = mhop.bt_chunk_size;
764d7019c0fSLijun Ou num_bt_l0 = mhop.ba_l0_num;
765d7019c0fSLijun Ou hop_num = mhop.hop_num;
766d7019c0fSLijun Ou
767a25d13cbSShaobo Xu obj_per_chunk = buf_chunk_size / obj_size;
76861b460d1SXi Wang num_hem = DIV_ROUND_UP(nobj, obj_per_chunk);
7692a3d923fSLijun Ou bt_chunk_num = bt_chunk_size / BA_BYTE_LEN;
77061b460d1SXi Wang
771215a8c09Soulijun if (type >= HEM_TYPE_MTT)
7726a93c77aSShaobo Xu num_bt_l0 = bt_chunk_num;
773a25d13cbSShaobo Xu
774a25d13cbSShaobo Xu table->hem = kcalloc(num_hem, sizeof(*table->hem),
775a25d13cbSShaobo Xu GFP_KERNEL);
776a25d13cbSShaobo Xu if (!table->hem)
777a25d13cbSShaobo Xu goto err_kcalloc_hem_buf;
778a25d13cbSShaobo Xu
779215a8c09Soulijun if (check_whether_bt_num_3(type, hop_num)) {
780a25d13cbSShaobo Xu unsigned long num_bt_l1;
781a25d13cbSShaobo Xu
78261b460d1SXi Wang num_bt_l1 = DIV_ROUND_UP(num_hem, bt_chunk_num);
783a25d13cbSShaobo Xu table->bt_l1 = kcalloc(num_bt_l1,
784a25d13cbSShaobo Xu sizeof(*table->bt_l1),
785a25d13cbSShaobo Xu GFP_KERNEL);
786a25d13cbSShaobo Xu if (!table->bt_l1)
787a25d13cbSShaobo Xu goto err_kcalloc_bt_l1;
788a25d13cbSShaobo Xu
789a25d13cbSShaobo Xu table->bt_l1_dma_addr = kcalloc(num_bt_l1,
790a25d13cbSShaobo Xu sizeof(*table->bt_l1_dma_addr),
791a25d13cbSShaobo Xu GFP_KERNEL);
792a25d13cbSShaobo Xu
793a25d13cbSShaobo Xu if (!table->bt_l1_dma_addr)
794a25d13cbSShaobo Xu goto err_kcalloc_l1_dma;
795a25d13cbSShaobo Xu }
796a25d13cbSShaobo Xu
797215a8c09Soulijun if (check_whether_bt_num_2(type, hop_num) ||
798215a8c09Soulijun check_whether_bt_num_3(type, hop_num)) {
799a25d13cbSShaobo Xu table->bt_l0 = kcalloc(num_bt_l0, sizeof(*table->bt_l0),
800a25d13cbSShaobo Xu GFP_KERNEL);
801a25d13cbSShaobo Xu if (!table->bt_l0)
802a25d13cbSShaobo Xu goto err_kcalloc_bt_l0;
803a25d13cbSShaobo Xu
804a25d13cbSShaobo Xu table->bt_l0_dma_addr = kcalloc(num_bt_l0,
805a25d13cbSShaobo Xu sizeof(*table->bt_l0_dma_addr),
806a25d13cbSShaobo Xu GFP_KERNEL);
807a25d13cbSShaobo Xu if (!table->bt_l0_dma_addr)
808a25d13cbSShaobo Xu goto err_kcalloc_l0_dma;
809a25d13cbSShaobo Xu }
810a25d13cbSShaobo Xu }
8119a443537Soulijun
8129a443537Soulijun table->type = type;
8139a443537Soulijun table->num_hem = num_hem;
8149a443537Soulijun table->obj_size = obj_size;
8159a443537Soulijun mutex_init(&table->mutex);
8169a443537Soulijun
8179a443537Soulijun return 0;
818a25d13cbSShaobo Xu
819a25d13cbSShaobo Xu err_kcalloc_l0_dma:
820a25d13cbSShaobo Xu kfree(table->bt_l0);
821a25d13cbSShaobo Xu table->bt_l0 = NULL;
822a25d13cbSShaobo Xu
823a25d13cbSShaobo Xu err_kcalloc_bt_l0:
824a25d13cbSShaobo Xu kfree(table->bt_l1_dma_addr);
825a25d13cbSShaobo Xu table->bt_l1_dma_addr = NULL;
826a25d13cbSShaobo Xu
827a25d13cbSShaobo Xu err_kcalloc_l1_dma:
828a25d13cbSShaobo Xu kfree(table->bt_l1);
829a25d13cbSShaobo Xu table->bt_l1 = NULL;
830a25d13cbSShaobo Xu
831a25d13cbSShaobo Xu err_kcalloc_bt_l1:
832a25d13cbSShaobo Xu kfree(table->hem);
833a25d13cbSShaobo Xu table->hem = NULL;
834a25d13cbSShaobo Xu
835a25d13cbSShaobo Xu err_kcalloc_hem_buf:
836a25d13cbSShaobo Xu return -ENOMEM;
837a25d13cbSShaobo Xu }
838a25d13cbSShaobo Xu
hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table)839281d0ccfSColin Ian King static void hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev *hr_dev,
840a25d13cbSShaobo Xu struct hns_roce_hem_table *table)
841a25d13cbSShaobo Xu {
842a25d13cbSShaobo Xu struct hns_roce_hem_mhop mhop;
843a25d13cbSShaobo Xu u32 buf_chunk_size;
844a25d13cbSShaobo Xu u64 obj;
845dc93a0d9SLang Cheng int i;
846a25d13cbSShaobo Xu
8470e20ebf8SLang Cheng if (hns_roce_calc_hem_mhop(hr_dev, table, NULL, &mhop))
8480e20ebf8SLang Cheng return;
8496a93c77aSShaobo Xu buf_chunk_size = table->type < HEM_TYPE_MTT ? mhop.buf_chunk_size :
8506a93c77aSShaobo Xu mhop.bt_chunk_size;
851a25d13cbSShaobo Xu
852a25d13cbSShaobo Xu for (i = 0; i < table->num_hem; ++i) {
853a25d13cbSShaobo Xu obj = i * buf_chunk_size / table->obj_size;
854a25d13cbSShaobo Xu if (table->hem[i])
855a25d13cbSShaobo Xu hns_roce_table_mhop_put(hr_dev, table, obj, 0);
856a25d13cbSShaobo Xu }
857a25d13cbSShaobo Xu
858a25d13cbSShaobo Xu kfree(table->hem);
859a25d13cbSShaobo Xu table->hem = NULL;
860a25d13cbSShaobo Xu kfree(table->bt_l1);
861a25d13cbSShaobo Xu table->bt_l1 = NULL;
862a25d13cbSShaobo Xu kfree(table->bt_l1_dma_addr);
863a25d13cbSShaobo Xu table->bt_l1_dma_addr = NULL;
864a25d13cbSShaobo Xu kfree(table->bt_l0);
865a25d13cbSShaobo Xu table->bt_l0 = NULL;
866a25d13cbSShaobo Xu kfree(table->bt_l0_dma_addr);
867a25d13cbSShaobo Xu table->bt_l0_dma_addr = NULL;
8689a443537Soulijun }
8699a443537Soulijun
hns_roce_cleanup_hem_table(struct hns_roce_dev * hr_dev,struct hns_roce_hem_table * table)8709a443537Soulijun void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev,
8719a443537Soulijun struct hns_roce_hem_table *table)
8729a443537Soulijun {
87313ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev;
8749a443537Soulijun unsigned long i;
875a519a612SChengchang Tang int obj;
876a519a612SChengchang Tang int ret;
8779a443537Soulijun
878a25d13cbSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) {
879a25d13cbSShaobo Xu hns_roce_cleanup_mhop_hem_table(hr_dev, table);
8809a84848dSwenglianfa mutex_destroy(&table->mutex);
881a25d13cbSShaobo Xu return;
882a25d13cbSShaobo Xu }
883a25d13cbSShaobo Xu
8849a443537Soulijun for (i = 0; i < table->num_hem; ++i)
8859a443537Soulijun if (table->hem[i]) {
886a519a612SChengchang Tang obj = i * table->table_chunk_size / table->obj_size;
887a519a612SChengchang Tang ret = hr_dev->hw->clear_hem(hr_dev, table, obj, 0);
888a519a612SChengchang Tang if (ret)
889a519a612SChengchang Tang dev_err(dev, "clear HEM base address failed, ret = %d.\n",
890a519a612SChengchang Tang ret);
8919a443537Soulijun
8929a443537Soulijun hns_roce_free_hem(hr_dev, table->hem[i]);
8939a443537Soulijun }
8949a443537Soulijun
8959a84848dSwenglianfa mutex_destroy(&table->mutex);
8969a443537Soulijun kfree(table->hem);
8979a443537Soulijun }
8989a443537Soulijun
hns_roce_cleanup_hem(struct hns_roce_dev * hr_dev)8999a443537Soulijun void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev)
9009a443537Soulijun {
9014ddeacf6SWenpeng Liang if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_SRQ)
9025c1f167aSLijun Ou hns_roce_cleanup_hem_table(hr_dev,
9035c1f167aSLijun Ou &hr_dev->srq_table.table);
9049a443537Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->cq_table.table);
9050e40dc2fSYangyang Li if (hr_dev->caps.qpc_timer_entry_sz)
9060e40dc2fSYangyang Li hns_roce_cleanup_hem_table(hr_dev,
9070e40dc2fSYangyang Li &hr_dev->qpc_timer_table);
9080e40dc2fSYangyang Li if (hr_dev->caps.cqc_timer_entry_sz)
9090e40dc2fSYangyang Li hns_roce_cleanup_hem_table(hr_dev,
9100e40dc2fSYangyang Li &hr_dev->cqc_timer_table);
9114ddeacf6SWenpeng Liang if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_QP_FLOW_CTRL)
9126a157f7dSYangyang Li hns_roce_cleanup_hem_table(hr_dev,
9136a157f7dSYangyang Li &hr_dev->qp_table.sccc_table);
914e92f2c18Soulijun if (hr_dev->caps.trrl_entry_sz)
915e92f2c18Soulijun hns_roce_cleanup_hem_table(hr_dev,
916e92f2c18Soulijun &hr_dev->qp_table.trrl_table);
917d6d91e46SWeihang Li
918d6d91e46SWeihang Li if (hr_dev->caps.gmv_entry_sz)
919d6d91e46SWeihang Li hns_roce_cleanup_hem_table(hr_dev, &hr_dev->gmv_table);
920d6d91e46SWeihang Li
921ae25db00Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.irrl_table);
9229a443537Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.qp_table);
9239a443537Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table);
9249a443537Soulijun }
92538389eaaSLijun Ou
9261f704d8cSXi Wang struct hns_roce_hem_item {
92738389eaaSLijun Ou struct list_head list; /* link all hems in the same bt level */
92838389eaaSLijun Ou struct list_head sibling; /* link all hems in last hop for mtt */
92938389eaaSLijun Ou void *addr;
93038389eaaSLijun Ou dma_addr_t dma_addr;
93138389eaaSLijun Ou size_t count; /* max ba numbers */
93238389eaaSLijun Ou int start; /* start buf offset in this hem */
93338389eaaSLijun Ou int end; /* end buf offset in this hem */
93438389eaaSLijun Ou };
93538389eaaSLijun Ou
9361f704d8cSXi Wang /* All HEM items are linked in a tree structure */
9371f704d8cSXi Wang struct hns_roce_hem_head {
9381f704d8cSXi Wang struct list_head branch[HNS_ROCE_MAX_BT_REGION];
9391f704d8cSXi Wang struct list_head root;
9401f704d8cSXi Wang struct list_head leaf;
9411f704d8cSXi Wang };
9421f704d8cSXi Wang
9431f704d8cSXi Wang static struct hns_roce_hem_item *
hem_list_alloc_item(struct hns_roce_dev * hr_dev,int start,int end,int count,bool exist_bt)9441f704d8cSXi Wang hem_list_alloc_item(struct hns_roce_dev *hr_dev, int start, int end, int count,
945be1eeb66SYunsheng Lin bool exist_bt)
94638389eaaSLijun Ou {
9471f704d8cSXi Wang struct hns_roce_hem_item *hem;
94838389eaaSLijun Ou
94938389eaaSLijun Ou hem = kzalloc(sizeof(*hem), GFP_KERNEL);
95038389eaaSLijun Ou if (!hem)
95138389eaaSLijun Ou return NULL;
95238389eaaSLijun Ou
95338389eaaSLijun Ou if (exist_bt) {
9549ea9a53eSXi Wang hem->addr = dma_alloc_coherent(hr_dev->dev, count * BA_BYTE_LEN,
95538389eaaSLijun Ou &hem->dma_addr, GFP_KERNEL);
95638389eaaSLijun Ou if (!hem->addr) {
95738389eaaSLijun Ou kfree(hem);
95838389eaaSLijun Ou return NULL;
95938389eaaSLijun Ou }
96038389eaaSLijun Ou }
96138389eaaSLijun Ou
96238389eaaSLijun Ou hem->count = count;
96338389eaaSLijun Ou hem->start = start;
96438389eaaSLijun Ou hem->end = end;
96538389eaaSLijun Ou INIT_LIST_HEAD(&hem->list);
96638389eaaSLijun Ou INIT_LIST_HEAD(&hem->sibling);
96738389eaaSLijun Ou
96838389eaaSLijun Ou return hem;
96938389eaaSLijun Ou }
97038389eaaSLijun Ou
hem_list_free_item(struct hns_roce_dev * hr_dev,struct hns_roce_hem_item * hem,bool exist_bt)97138389eaaSLijun Ou static void hem_list_free_item(struct hns_roce_dev *hr_dev,
9721f704d8cSXi Wang struct hns_roce_hem_item *hem, bool exist_bt)
97338389eaaSLijun Ou {
97438389eaaSLijun Ou if (exist_bt)
97538389eaaSLijun Ou dma_free_coherent(hr_dev->dev, hem->count * BA_BYTE_LEN,
97638389eaaSLijun Ou hem->addr, hem->dma_addr);
97738389eaaSLijun Ou kfree(hem);
97838389eaaSLijun Ou }
97938389eaaSLijun Ou
hem_list_free_all(struct hns_roce_dev * hr_dev,struct list_head * head,bool exist_bt)98038389eaaSLijun Ou static void hem_list_free_all(struct hns_roce_dev *hr_dev,
98138389eaaSLijun Ou struct list_head *head, bool exist_bt)
98238389eaaSLijun Ou {
9831f704d8cSXi Wang struct hns_roce_hem_item *hem, *temp_hem;
98438389eaaSLijun Ou
98538389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, head, list) {
98638389eaaSLijun Ou list_del(&hem->list);
98738389eaaSLijun Ou hem_list_free_item(hr_dev, hem, exist_bt);
98838389eaaSLijun Ou }
98938389eaaSLijun Ou }
99038389eaaSLijun Ou
hem_list_link_bt(void * base_addr,u64 table_addr)991f4caa864SChengchang Tang static void hem_list_link_bt(void *base_addr, u64 table_addr)
99238389eaaSLijun Ou {
99338389eaaSLijun Ou *(u64 *)(base_addr) = table_addr;
99438389eaaSLijun Ou }
99538389eaaSLijun Ou
99638389eaaSLijun Ou /* assign L0 table address to hem from root bt */
hem_list_assign_bt(struct hns_roce_hem_item * hem,void * cpu_addr,u64 phy_addr)997f4caa864SChengchang Tang static void hem_list_assign_bt(struct hns_roce_hem_item *hem, void *cpu_addr,
99838389eaaSLijun Ou u64 phy_addr)
99938389eaaSLijun Ou {
100038389eaaSLijun Ou hem->addr = cpu_addr;
100138389eaaSLijun Ou hem->dma_addr = (dma_addr_t)phy_addr;
100238389eaaSLijun Ou }
100338389eaaSLijun Ou
hem_list_page_is_in_range(struct hns_roce_hem_item * hem,int offset)10041f704d8cSXi Wang static inline bool hem_list_page_is_in_range(struct hns_roce_hem_item *hem,
100538389eaaSLijun Ou int offset)
100638389eaaSLijun Ou {
100738389eaaSLijun Ou return (hem->start <= offset && offset <= hem->end);
100838389eaaSLijun Ou }
100938389eaaSLijun Ou
hem_list_search_item(struct list_head * ba_list,int page_offset)10101f704d8cSXi Wang static struct hns_roce_hem_item *hem_list_search_item(struct list_head *ba_list,
101138389eaaSLijun Ou int page_offset)
101238389eaaSLijun Ou {
10131f704d8cSXi Wang struct hns_roce_hem_item *hem, *temp_hem;
10141f704d8cSXi Wang struct hns_roce_hem_item *found = NULL;
101538389eaaSLijun Ou
101638389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, ba_list, list) {
101738389eaaSLijun Ou if (hem_list_page_is_in_range(hem, page_offset)) {
101838389eaaSLijun Ou found = hem;
101938389eaaSLijun Ou break;
102038389eaaSLijun Ou }
102138389eaaSLijun Ou }
102238389eaaSLijun Ou
102338389eaaSLijun Ou return found;
102438389eaaSLijun Ou }
102538389eaaSLijun Ou
hem_list_is_bottom_bt(int hopnum,int bt_level)102638389eaaSLijun Ou static bool hem_list_is_bottom_bt(int hopnum, int bt_level)
102738389eaaSLijun Ou {
102838389eaaSLijun Ou /*
102938389eaaSLijun Ou * hopnum base address table levels
103038389eaaSLijun Ou * 0 L0(buf)
103138389eaaSLijun Ou * 1 L0 -> buf
103238389eaaSLijun Ou * 2 L0 -> L1 -> buf
103338389eaaSLijun Ou * 3 L0 -> L1 -> L2 -> buf
103438389eaaSLijun Ou */
103538389eaaSLijun Ou return bt_level >= (hopnum ? hopnum - 1 : hopnum);
103638389eaaSLijun Ou }
103738389eaaSLijun Ou
1038bf194997SLeon Romanovsky /*
103938389eaaSLijun Ou * calc base address entries num
104038389eaaSLijun Ou * @hopnum: num of mutihop addressing
104138389eaaSLijun Ou * @bt_level: base address table level
104238389eaaSLijun Ou * @unit: ba entries per bt page
104338389eaaSLijun Ou */
hem_list_calc_ba_range(int hopnum,int bt_level,int unit)1044d586628bSwenglianfa static u64 hem_list_calc_ba_range(int hopnum, int bt_level, int unit)
104538389eaaSLijun Ou {
1046d586628bSwenglianfa u64 step;
104738389eaaSLijun Ou int max;
104838389eaaSLijun Ou int i;
104938389eaaSLijun Ou
105038389eaaSLijun Ou if (hopnum <= bt_level)
105138389eaaSLijun Ou return 0;
105238389eaaSLijun Ou /*
105338389eaaSLijun Ou * hopnum bt_level range
105438389eaaSLijun Ou * 1 0 unit
105538389eaaSLijun Ou * ------------
105638389eaaSLijun Ou * 2 0 unit * unit
105738389eaaSLijun Ou * 2 1 unit
105838389eaaSLijun Ou * ------------
105938389eaaSLijun Ou * 3 0 unit * unit * unit
106038389eaaSLijun Ou * 3 1 unit * unit
106138389eaaSLijun Ou * 3 2 unit
106238389eaaSLijun Ou */
106338389eaaSLijun Ou step = 1;
106438389eaaSLijun Ou max = hopnum - bt_level;
106538389eaaSLijun Ou for (i = 0; i < max; i++)
106638389eaaSLijun Ou step = step * unit;
106738389eaaSLijun Ou
106838389eaaSLijun Ou return step;
106938389eaaSLijun Ou }
107038389eaaSLijun Ou
1071bf194997SLeon Romanovsky /*
107238389eaaSLijun Ou * calc the root ba entries which could cover all regions
107338389eaaSLijun Ou * @regions: buf region array
107438389eaaSLijun Ou * @region_cnt: array size of @regions
107538389eaaSLijun Ou * @unit: ba entries per bt page
107638389eaaSLijun Ou */
hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region * regions,int region_cnt,int unit)107738389eaaSLijun Ou int hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region *regions,
107838389eaaSLijun Ou int region_cnt, int unit)
107938389eaaSLijun Ou {
108038389eaaSLijun Ou struct hns_roce_buf_region *r;
108138389eaaSLijun Ou int total = 0;
1082d586628bSwenglianfa u64 step;
108338389eaaSLijun Ou int i;
108438389eaaSLijun Ou
108538389eaaSLijun Ou for (i = 0; i < region_cnt; i++) {
108638389eaaSLijun Ou r = (struct hns_roce_buf_region *)®ions[i];
108738389eaaSLijun Ou if (r->hopnum > 1) {
108838389eaaSLijun Ou step = hem_list_calc_ba_range(r->hopnum, 1, unit);
108938389eaaSLijun Ou if (step > 0)
109038389eaaSLijun Ou total += (r->count + step - 1) / step;
109138389eaaSLijun Ou } else {
109238389eaaSLijun Ou total += r->count;
109338389eaaSLijun Ou }
109438389eaaSLijun Ou }
109538389eaaSLijun Ou
109638389eaaSLijun Ou return total;
109738389eaaSLijun Ou }
109838389eaaSLijun Ou
hem_list_alloc_mid_bt(struct hns_roce_dev * hr_dev,const struct hns_roce_buf_region * r,int unit,int offset,struct list_head * mid_bt,struct list_head * btm_bt)109938389eaaSLijun Ou static int hem_list_alloc_mid_bt(struct hns_roce_dev *hr_dev,
110038389eaaSLijun Ou const struct hns_roce_buf_region *r, int unit,
110138389eaaSLijun Ou int offset, struct list_head *mid_bt,
110238389eaaSLijun Ou struct list_head *btm_bt)
110338389eaaSLijun Ou {
11041f704d8cSXi Wang struct hns_roce_hem_item *hem_ptrs[HNS_ROCE_MAX_BT_LEVEL] = { NULL };
110538389eaaSLijun Ou struct list_head temp_list[HNS_ROCE_MAX_BT_LEVEL];
11061f704d8cSXi Wang struct hns_roce_hem_item *cur, *pre;
110738389eaaSLijun Ou const int hopnum = r->hopnum;
110838389eaaSLijun Ou int start_aligned;
110938389eaaSLijun Ou int distance;
111038389eaaSLijun Ou int ret = 0;
111138389eaaSLijun Ou int max_ofs;
111238389eaaSLijun Ou int level;
1113d586628bSwenglianfa u64 step;
111438389eaaSLijun Ou int end;
111538389eaaSLijun Ou
111638389eaaSLijun Ou if (hopnum <= 1)
111738389eaaSLijun Ou return 0;
111838389eaaSLijun Ou
111938389eaaSLijun Ou if (hopnum > HNS_ROCE_MAX_BT_LEVEL) {
112038389eaaSLijun Ou dev_err(hr_dev->dev, "invalid hopnum %d!\n", hopnum);
112138389eaaSLijun Ou return -EINVAL;
112238389eaaSLijun Ou }
112338389eaaSLijun Ou
112438389eaaSLijun Ou if (offset < r->offset) {
112561918e9bSYixing Liu dev_err(hr_dev->dev, "invalid offset %d, min %u!\n",
112638389eaaSLijun Ou offset, r->offset);
112738389eaaSLijun Ou return -EINVAL;
112838389eaaSLijun Ou }
112938389eaaSLijun Ou
113038389eaaSLijun Ou distance = offset - r->offset;
113138389eaaSLijun Ou max_ofs = r->offset + r->count - 1;
113238389eaaSLijun Ou for (level = 0; level < hopnum; level++)
113338389eaaSLijun Ou INIT_LIST_HEAD(&temp_list[level]);
113438389eaaSLijun Ou
113538389eaaSLijun Ou /* config L1 bt to last bt and link them to corresponding parent */
113638389eaaSLijun Ou for (level = 1; level < hopnum; level++) {
1137*fe51f625SJunxian Huang if (!hem_list_is_bottom_bt(hopnum, level)) {
113838389eaaSLijun Ou cur = hem_list_search_item(&mid_bt[level], offset);
113938389eaaSLijun Ou if (cur) {
114038389eaaSLijun Ou hem_ptrs[level] = cur;
114138389eaaSLijun Ou continue;
114238389eaaSLijun Ou }
1143*fe51f625SJunxian Huang }
114438389eaaSLijun Ou
114538389eaaSLijun Ou step = hem_list_calc_ba_range(hopnum, level, unit);
114638389eaaSLijun Ou if (step < 1) {
114738389eaaSLijun Ou ret = -EINVAL;
114838389eaaSLijun Ou goto err_exit;
114938389eaaSLijun Ou }
115038389eaaSLijun Ou
115138389eaaSLijun Ou start_aligned = (distance / step) * step + r->offset;
1152d586628bSwenglianfa end = min_t(u64, start_aligned + step - 1, max_ofs);
115338389eaaSLijun Ou cur = hem_list_alloc_item(hr_dev, start_aligned, end, unit,
1154be1eeb66SYunsheng Lin true);
115538389eaaSLijun Ou if (!cur) {
115638389eaaSLijun Ou ret = -ENOMEM;
115738389eaaSLijun Ou goto err_exit;
115838389eaaSLijun Ou }
115938389eaaSLijun Ou hem_ptrs[level] = cur;
116038389eaaSLijun Ou list_add(&cur->list, &temp_list[level]);
116138389eaaSLijun Ou if (hem_list_is_bottom_bt(hopnum, level))
116238389eaaSLijun Ou list_add(&cur->sibling, &temp_list[0]);
116338389eaaSLijun Ou
116438389eaaSLijun Ou /* link bt to parent bt */
116538389eaaSLijun Ou if (level > 1) {
116638389eaaSLijun Ou pre = hem_ptrs[level - 1];
116738389eaaSLijun Ou step = (cur->start - pre->start) / step * BA_BYTE_LEN;
1168f4caa864SChengchang Tang hem_list_link_bt(pre->addr + step, cur->dma_addr);
116938389eaaSLijun Ou }
117038389eaaSLijun Ou }
117138389eaaSLijun Ou
117238389eaaSLijun Ou list_splice(&temp_list[0], btm_bt);
117338389eaaSLijun Ou for (level = 1; level < hopnum; level++)
117438389eaaSLijun Ou list_splice(&temp_list[level], &mid_bt[level]);
117538389eaaSLijun Ou
117638389eaaSLijun Ou return 0;
117738389eaaSLijun Ou
117838389eaaSLijun Ou err_exit:
117938389eaaSLijun Ou for (level = 1; level < hopnum; level++)
118038389eaaSLijun Ou hem_list_free_all(hr_dev, &temp_list[level], true);
118138389eaaSLijun Ou
118238389eaaSLijun Ou return ret;
118338389eaaSLijun Ou }
118438389eaaSLijun Ou
11851f704d8cSXi Wang static struct hns_roce_hem_item *
alloc_root_hem(struct hns_roce_dev * hr_dev,int unit,int * max_ba_num,const struct hns_roce_buf_region * regions,int region_cnt)11861f704d8cSXi Wang alloc_root_hem(struct hns_roce_dev *hr_dev, int unit, int *max_ba_num,
11871f704d8cSXi Wang const struct hns_roce_buf_region *regions, int region_cnt)
118838389eaaSLijun Ou {
118938389eaaSLijun Ou const struct hns_roce_buf_region *r;
11901f704d8cSXi Wang struct hns_roce_hem_item *hem;
119111334014SXi Wang int ba_num;
119238389eaaSLijun Ou int offset;
119338389eaaSLijun Ou
119411334014SXi Wang ba_num = hns_roce_hem_list_calc_root_ba(regions, region_cnt, unit);
119511334014SXi Wang if (ba_num < 1)
11961f704d8cSXi Wang return ERR_PTR(-ENOMEM);
119711334014SXi Wang
11989ea9a53eSXi Wang if (ba_num > unit)
11991f704d8cSXi Wang return ERR_PTR(-ENOBUFS);
12009ea9a53eSXi Wang
12011f704d8cSXi Wang offset = regions[0].offset;
120238389eaaSLijun Ou /* indicate to last region */
120338389eaaSLijun Ou r = ®ions[region_cnt - 1];
12041f704d8cSXi Wang hem = hem_list_alloc_item(hr_dev, offset, r->offset + r->count - 1,
1205be1eeb66SYunsheng Lin ba_num, true);
12061f704d8cSXi Wang if (!hem)
12071f704d8cSXi Wang return ERR_PTR(-ENOMEM);
12081f704d8cSXi Wang
12091f704d8cSXi Wang *max_ba_num = ba_num;
12101f704d8cSXi Wang
12111f704d8cSXi Wang return hem;
12121f704d8cSXi Wang }
12131f704d8cSXi Wang
alloc_fake_root_bt(struct hns_roce_dev * hr_dev,void * cpu_base,u64 phy_base,const struct hns_roce_buf_region * r,struct list_head * branch_head,struct list_head * leaf_head)12141f704d8cSXi Wang static int alloc_fake_root_bt(struct hns_roce_dev *hr_dev, void *cpu_base,
12151f704d8cSXi Wang u64 phy_base, const struct hns_roce_buf_region *r,
12161f704d8cSXi Wang struct list_head *branch_head,
12171f704d8cSXi Wang struct list_head *leaf_head)
12181f704d8cSXi Wang {
12191f704d8cSXi Wang struct hns_roce_hem_item *hem;
12201f704d8cSXi Wang
12211f704d8cSXi Wang hem = hem_list_alloc_item(hr_dev, r->offset, r->offset + r->count - 1,
1222be1eeb66SYunsheng Lin r->count, false);
12231f704d8cSXi Wang if (!hem)
12241f704d8cSXi Wang return -ENOMEM;
12251f704d8cSXi Wang
1226f4caa864SChengchang Tang hem_list_assign_bt(hem, cpu_base, phy_base);
12271f704d8cSXi Wang list_add(&hem->list, branch_head);
12281f704d8cSXi Wang list_add(&hem->sibling, leaf_head);
12291f704d8cSXi Wang
12301f704d8cSXi Wang return r->count;
12311f704d8cSXi Wang }
12321f704d8cSXi Wang
setup_middle_bt(struct hns_roce_dev * hr_dev,void * cpu_base,int unit,const struct hns_roce_buf_region * r,const struct list_head * branch_head)12331f704d8cSXi Wang static int setup_middle_bt(struct hns_roce_dev *hr_dev, void *cpu_base,
12341f704d8cSXi Wang int unit, const struct hns_roce_buf_region *r,
12351f704d8cSXi Wang const struct list_head *branch_head)
12361f704d8cSXi Wang {
12371f704d8cSXi Wang struct hns_roce_hem_item *hem, *temp_hem;
12381f704d8cSXi Wang int total = 0;
12391f704d8cSXi Wang int offset;
1240d586628bSwenglianfa u64 step;
12411f704d8cSXi Wang
12421f704d8cSXi Wang step = hem_list_calc_ba_range(r->hopnum, 1, unit);
12431f704d8cSXi Wang if (step < 1)
12441f704d8cSXi Wang return -EINVAL;
12451f704d8cSXi Wang
12461f704d8cSXi Wang /* if exist mid bt, link L1 to L0 */
12471f704d8cSXi Wang list_for_each_entry_safe(hem, temp_hem, branch_head, list) {
12481f704d8cSXi Wang offset = (hem->start - r->offset) / step * BA_BYTE_LEN;
1249f4caa864SChengchang Tang hem_list_link_bt(cpu_base + offset, hem->dma_addr);
12501f704d8cSXi Wang total++;
12511f704d8cSXi Wang }
12521f704d8cSXi Wang
12531f704d8cSXi Wang return total;
12541f704d8cSXi Wang }
12551f704d8cSXi Wang
12561f704d8cSXi Wang static int
setup_root_hem(struct hns_roce_dev * hr_dev,struct hns_roce_hem_list * hem_list,int unit,int max_ba_num,struct hns_roce_hem_head * head,const struct hns_roce_buf_region * regions,int region_cnt)12571f704d8cSXi Wang setup_root_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem_list *hem_list,
12581f704d8cSXi Wang int unit, int max_ba_num, struct hns_roce_hem_head *head,
12591f704d8cSXi Wang const struct hns_roce_buf_region *regions, int region_cnt)
12601f704d8cSXi Wang {
12611f704d8cSXi Wang const struct hns_roce_buf_region *r;
12621f704d8cSXi Wang struct hns_roce_hem_item *root_hem;
12631f704d8cSXi Wang void *cpu_base;
12641f704d8cSXi Wang u64 phy_base;
12651f704d8cSXi Wang int i, total;
12661f704d8cSXi Wang int ret;
12671f704d8cSXi Wang
12681f704d8cSXi Wang root_hem = list_first_entry(&head->root,
12691f704d8cSXi Wang struct hns_roce_hem_item, list);
127038389eaaSLijun Ou if (!root_hem)
127138389eaaSLijun Ou return -ENOMEM;
127238389eaaSLijun Ou
127338389eaaSLijun Ou total = 0;
12741f704d8cSXi Wang for (i = 0; i < region_cnt && total < max_ba_num; i++) {
127538389eaaSLijun Ou r = ®ions[i];
127638389eaaSLijun Ou if (!r->count)
127738389eaaSLijun Ou continue;
127838389eaaSLijun Ou
127938389eaaSLijun Ou /* all regions's mid[x][0] shared the root_bt's trunk */
128038389eaaSLijun Ou cpu_base = root_hem->addr + total * BA_BYTE_LEN;
128138389eaaSLijun Ou phy_base = root_hem->dma_addr + total * BA_BYTE_LEN;
128238389eaaSLijun Ou
128338389eaaSLijun Ou /* if hopnum is 0 or 1, cut a new fake hem from the root bt
128438389eaaSLijun Ou * which's address share to all regions.
128538389eaaSLijun Ou */
12861f704d8cSXi Wang if (hem_list_is_bottom_bt(r->hopnum, 0))
12871f704d8cSXi Wang ret = alloc_fake_root_bt(hr_dev, cpu_base, phy_base, r,
12881f704d8cSXi Wang &head->branch[i], &head->leaf);
12891f704d8cSXi Wang else
12901f704d8cSXi Wang ret = setup_middle_bt(hr_dev, cpu_base, unit, r,
12911f704d8cSXi Wang &hem_list->mid_bt[i][1]);
12921f704d8cSXi Wang
12931f704d8cSXi Wang if (ret < 0)
12941f704d8cSXi Wang return ret;
12951f704d8cSXi Wang
12961f704d8cSXi Wang total += ret;
129738389eaaSLijun Ou }
129838389eaaSLijun Ou
12991f704d8cSXi Wang list_splice(&head->leaf, &hem_list->btm_bt);
13001f704d8cSXi Wang list_splice(&head->root, &hem_list->root_bt);
130138389eaaSLijun Ou for (i = 0; i < region_cnt; i++)
13021f704d8cSXi Wang list_splice(&head->branch[i], &hem_list->mid_bt[i][0]);
130338389eaaSLijun Ou
130438389eaaSLijun Ou return 0;
13051f704d8cSXi Wang }
130638389eaaSLijun Ou
hem_list_alloc_root_bt(struct hns_roce_dev * hr_dev,struct hns_roce_hem_list * hem_list,int unit,const struct hns_roce_buf_region * regions,int region_cnt)13071f704d8cSXi Wang static int hem_list_alloc_root_bt(struct hns_roce_dev *hr_dev,
13081f704d8cSXi Wang struct hns_roce_hem_list *hem_list, int unit,
13091f704d8cSXi Wang const struct hns_roce_buf_region *regions,
13101f704d8cSXi Wang int region_cnt)
13111f704d8cSXi Wang {
13121f704d8cSXi Wang struct hns_roce_hem_item *root_hem;
13131f704d8cSXi Wang struct hns_roce_hem_head head;
13141f704d8cSXi Wang int max_ba_num;
13151f704d8cSXi Wang int ret;
13161f704d8cSXi Wang int i;
13171f704d8cSXi Wang
13181f704d8cSXi Wang root_hem = hem_list_search_item(&hem_list->root_bt, regions[0].offset);
13191f704d8cSXi Wang if (root_hem)
13201f704d8cSXi Wang return 0;
13211f704d8cSXi Wang
13221f704d8cSXi Wang max_ba_num = 0;
13231f704d8cSXi Wang root_hem = alloc_root_hem(hr_dev, unit, &max_ba_num, regions,
13241f704d8cSXi Wang region_cnt);
13251f704d8cSXi Wang if (IS_ERR(root_hem))
13261f704d8cSXi Wang return PTR_ERR(root_hem);
13271f704d8cSXi Wang
13281f704d8cSXi Wang /* List head for storing all allocated HEM items */
13291f704d8cSXi Wang INIT_LIST_HEAD(&head.root);
13301f704d8cSXi Wang INIT_LIST_HEAD(&head.leaf);
133138389eaaSLijun Ou for (i = 0; i < region_cnt; i++)
13321f704d8cSXi Wang INIT_LIST_HEAD(&head.branch[i]);
133338389eaaSLijun Ou
13341f704d8cSXi Wang hem_list->root_ba = root_hem->dma_addr;
13351f704d8cSXi Wang list_add(&root_hem->list, &head.root);
13361f704d8cSXi Wang ret = setup_root_hem(hr_dev, hem_list, unit, max_ba_num, &head, regions,
13371f704d8cSXi Wang region_cnt);
13381f704d8cSXi Wang if (ret) {
13391f704d8cSXi Wang for (i = 0; i < region_cnt; i++)
13401f704d8cSXi Wang hem_list_free_all(hr_dev, &head.branch[i], false);
13411f704d8cSXi Wang
13421f704d8cSXi Wang hem_list_free_all(hr_dev, &head.root, true);
13431f704d8cSXi Wang }
134438389eaaSLijun Ou
134538389eaaSLijun Ou return ret;
134638389eaaSLijun Ou }
134738389eaaSLijun Ou
134838389eaaSLijun Ou /* construct the base address table and link them by address hop config */
hns_roce_hem_list_request(struct hns_roce_dev * hr_dev,struct hns_roce_hem_list * hem_list,const struct hns_roce_buf_region * regions,int region_cnt,unsigned int bt_pg_shift)134938389eaaSLijun Ou int hns_roce_hem_list_request(struct hns_roce_dev *hr_dev,
135038389eaaSLijun Ou struct hns_roce_hem_list *hem_list,
135138389eaaSLijun Ou const struct hns_roce_buf_region *regions,
135282d07a4eSWeihang Li int region_cnt, unsigned int bt_pg_shift)
135338389eaaSLijun Ou {
135438389eaaSLijun Ou const struct hns_roce_buf_region *r;
135538389eaaSLijun Ou int ofs, end;
135638389eaaSLijun Ou int unit;
1357dc93a0d9SLang Cheng int ret;
135838389eaaSLijun Ou int i;
135938389eaaSLijun Ou
136038389eaaSLijun Ou if (region_cnt > HNS_ROCE_MAX_BT_REGION) {
136138389eaaSLijun Ou dev_err(hr_dev->dev, "invalid region region_cnt %d!\n",
136238389eaaSLijun Ou region_cnt);
136338389eaaSLijun Ou return -EINVAL;
136438389eaaSLijun Ou }
136538389eaaSLijun Ou
13663c873161SXi Wang unit = (1 << bt_pg_shift) / BA_BYTE_LEN;
136738389eaaSLijun Ou for (i = 0; i < region_cnt; i++) {
136838389eaaSLijun Ou r = ®ions[i];
136938389eaaSLijun Ou if (!r->count)
137038389eaaSLijun Ou continue;
137138389eaaSLijun Ou
137238389eaaSLijun Ou end = r->offset + r->count;
137338389eaaSLijun Ou for (ofs = r->offset; ofs < end; ofs += unit) {
137438389eaaSLijun Ou ret = hem_list_alloc_mid_bt(hr_dev, r, unit, ofs,
137538389eaaSLijun Ou hem_list->mid_bt[i],
137638389eaaSLijun Ou &hem_list->btm_bt);
137738389eaaSLijun Ou if (ret) {
137838389eaaSLijun Ou dev_err(hr_dev->dev,
137938389eaaSLijun Ou "alloc hem trunk fail ret = %d!\n", ret);
138038389eaaSLijun Ou goto err_alloc;
138138389eaaSLijun Ou }
138238389eaaSLijun Ou }
138338389eaaSLijun Ou }
138438389eaaSLijun Ou
138538389eaaSLijun Ou ret = hem_list_alloc_root_bt(hr_dev, hem_list, unit, regions,
138638389eaaSLijun Ou region_cnt);
138738389eaaSLijun Ou if (ret)
138838389eaaSLijun Ou dev_err(hr_dev->dev, "alloc hem root fail ret = %d!\n", ret);
138938389eaaSLijun Ou else
139038389eaaSLijun Ou return 0;
139138389eaaSLijun Ou
139238389eaaSLijun Ou err_alloc:
139338389eaaSLijun Ou hns_roce_hem_list_release(hr_dev, hem_list);
139438389eaaSLijun Ou
139538389eaaSLijun Ou return ret;
139638389eaaSLijun Ou }
139738389eaaSLijun Ou
hns_roce_hem_list_release(struct hns_roce_dev * hr_dev,struct hns_roce_hem_list * hem_list)139838389eaaSLijun Ou void hns_roce_hem_list_release(struct hns_roce_dev *hr_dev,
139938389eaaSLijun Ou struct hns_roce_hem_list *hem_list)
140038389eaaSLijun Ou {
140138389eaaSLijun Ou int i, j;
140238389eaaSLijun Ou
140338389eaaSLijun Ou for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)
140438389eaaSLijun Ou for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)
140538389eaaSLijun Ou hem_list_free_all(hr_dev, &hem_list->mid_bt[i][j],
140638389eaaSLijun Ou j != 0);
140738389eaaSLijun Ou
140838389eaaSLijun Ou hem_list_free_all(hr_dev, &hem_list->root_bt, true);
140938389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->btm_bt);
141038389eaaSLijun Ou hem_list->root_ba = 0;
141138389eaaSLijun Ou }
141238389eaaSLijun Ou
hns_roce_hem_list_init(struct hns_roce_hem_list * hem_list)14133c873161SXi Wang void hns_roce_hem_list_init(struct hns_roce_hem_list *hem_list)
141438389eaaSLijun Ou {
141538389eaaSLijun Ou int i, j;
141638389eaaSLijun Ou
141738389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->root_bt);
141838389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->btm_bt);
141938389eaaSLijun Ou for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++)
142038389eaaSLijun Ou for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++)
142138389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->mid_bt[i][j]);
142238389eaaSLijun Ou }
142338389eaaSLijun Ou
hns_roce_hem_list_find_mtt(struct hns_roce_dev * hr_dev,struct hns_roce_hem_list * hem_list,int offset,int * mtt_cnt)142438389eaaSLijun Ou void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev,
142538389eaaSLijun Ou struct hns_roce_hem_list *hem_list,
14265f652387SChengchang Tang int offset, int *mtt_cnt)
142738389eaaSLijun Ou {
142838389eaaSLijun Ou struct list_head *head = &hem_list->btm_bt;
14291f704d8cSXi Wang struct hns_roce_hem_item *hem, *temp_hem;
143038389eaaSLijun Ou void *cpu_base = NULL;
143138389eaaSLijun Ou int nr = 0;
143238389eaaSLijun Ou
143338389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, head, sibling) {
143438389eaaSLijun Ou if (hem_list_page_is_in_range(hem, offset)) {
143538389eaaSLijun Ou nr = offset - hem->start;
143638389eaaSLijun Ou cpu_base = hem->addr + nr * BA_BYTE_LEN;
143738389eaaSLijun Ou nr = hem->end + 1 - offset;
143838389eaaSLijun Ou break;
143938389eaaSLijun Ou }
144038389eaaSLijun Ou }
144138389eaaSLijun Ou
144238389eaaSLijun Ou if (mtt_cnt)
144338389eaaSLijun Ou *mtt_cnt = nr;
144438389eaaSLijun Ou
144538389eaaSLijun Ou return cpu_base;
144638389eaaSLijun Ou }
1447