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 <linux/platform_device.h> 359a443537Soulijun #include "hns_roce_device.h" 369a443537Soulijun #include "hns_roce_hem.h" 379a443537Soulijun #include "hns_roce_common.h" 389a443537Soulijun 399a443537Soulijun #define DMA_ADDR_T_SHIFT 12 409a443537Soulijun #define BT_BA_SHIFT 32 419a443537Soulijun 42a25d13cbSShaobo Xu bool hns_roce_check_whether_mhop(struct hns_roce_dev *hr_dev, u32 type) 43a25d13cbSShaobo Xu { 44*d7019c0fSLijun Ou int hop_num = 0; 45a25d13cbSShaobo Xu 46*d7019c0fSLijun Ou switch (type) { 47*d7019c0fSLijun Ou case HEM_TYPE_QPC: 48*d7019c0fSLijun Ou hop_num = hr_dev->caps.qpc_hop_num; 49*d7019c0fSLijun Ou break; 50*d7019c0fSLijun Ou case HEM_TYPE_MTPT: 51*d7019c0fSLijun Ou hop_num = hr_dev->caps.mpt_hop_num; 52*d7019c0fSLijun Ou break; 53*d7019c0fSLijun Ou case HEM_TYPE_CQC: 54*d7019c0fSLijun Ou hop_num = hr_dev->caps.cqc_hop_num; 55*d7019c0fSLijun Ou break; 56*d7019c0fSLijun Ou case HEM_TYPE_SRQC: 57*d7019c0fSLijun Ou hop_num = hr_dev->caps.srqc_hop_num; 58*d7019c0fSLijun Ou break; 59*d7019c0fSLijun Ou case HEM_TYPE_SCCC: 60*d7019c0fSLijun Ou hop_num = hr_dev->caps.sccc_hop_num; 61*d7019c0fSLijun Ou break; 62*d7019c0fSLijun Ou case HEM_TYPE_QPC_TIMER: 63*d7019c0fSLijun Ou hop_num = hr_dev->caps.qpc_timer_hop_num; 64*d7019c0fSLijun Ou break; 65*d7019c0fSLijun Ou case HEM_TYPE_CQC_TIMER: 66*d7019c0fSLijun Ou hop_num = hr_dev->caps.cqc_timer_hop_num; 67*d7019c0fSLijun Ou break; 68*d7019c0fSLijun Ou case HEM_TYPE_CQE: 69*d7019c0fSLijun Ou hop_num = hr_dev->caps.cqe_hop_num; 70*d7019c0fSLijun Ou break; 71*d7019c0fSLijun Ou case HEM_TYPE_MTT: 72*d7019c0fSLijun Ou hop_num = hr_dev->caps.mtt_hop_num; 73*d7019c0fSLijun Ou break; 74*d7019c0fSLijun Ou case HEM_TYPE_SRQWQE: 75*d7019c0fSLijun Ou hop_num = hr_dev->caps.srqwqe_hop_num; 76*d7019c0fSLijun Ou break; 77*d7019c0fSLijun Ou case HEM_TYPE_IDX: 78*d7019c0fSLijun Ou hop_num = hr_dev->caps.idx_hop_num; 79*d7019c0fSLijun Ou break; 80*d7019c0fSLijun Ou default: 81a25d13cbSShaobo Xu return false; 82a25d13cbSShaobo Xu } 83a25d13cbSShaobo Xu 84*d7019c0fSLijun Ou return hop_num ? true : false; 85*d7019c0fSLijun Ou } 86*d7019c0fSLijun Ou 87a25d13cbSShaobo Xu static bool hns_roce_check_hem_null(struct hns_roce_hem **hem, u64 start_idx, 88a25d13cbSShaobo Xu u32 bt_chunk_num) 89a25d13cbSShaobo Xu { 90a25d13cbSShaobo Xu int i; 91a25d13cbSShaobo Xu 92a25d13cbSShaobo Xu for (i = 0; i < bt_chunk_num; i++) 93a25d13cbSShaobo Xu if (hem[start_idx + i]) 94a25d13cbSShaobo Xu return false; 95a25d13cbSShaobo Xu 96a25d13cbSShaobo Xu return true; 97a25d13cbSShaobo Xu } 98a25d13cbSShaobo Xu 99a25d13cbSShaobo Xu static bool hns_roce_check_bt_null(u64 **bt, u64 start_idx, u32 bt_chunk_num) 100a25d13cbSShaobo Xu { 101a25d13cbSShaobo Xu int i; 102a25d13cbSShaobo Xu 103a25d13cbSShaobo Xu for (i = 0; i < bt_chunk_num; i++) 104a25d13cbSShaobo Xu if (bt[start_idx + i]) 105a25d13cbSShaobo Xu return false; 106a25d13cbSShaobo Xu 107a25d13cbSShaobo Xu return true; 108a25d13cbSShaobo Xu } 109a25d13cbSShaobo Xu 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 122*d7019c0fSLijun Ou static int get_hem_table_config(struct hns_roce_dev *hr_dev, 123*d7019c0fSLijun Ou struct hns_roce_hem_mhop *mhop, 124*d7019c0fSLijun Ou u32 type) 125a25d13cbSShaobo Xu { 126a25d13cbSShaobo Xu struct device *dev = hr_dev->dev; 127a25d13cbSShaobo Xu 128*d7019c0fSLijun 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; 1856a93c77aSShaobo Xu case HEM_TYPE_MTT: 1866a93c77aSShaobo Xu mhop->buf_chunk_size = 1 << (hr_dev->caps.mtt_buf_pg_sz 1876a93c77aSShaobo Xu + PAGE_SHIFT); 1886a93c77aSShaobo Xu mhop->bt_chunk_size = 1 << (hr_dev->caps.mtt_ba_pg_sz 1896a93c77aSShaobo Xu + PAGE_SHIFT); 1902a3d923fSLijun Ou mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN; 1916a93c77aSShaobo Xu mhop->hop_num = hr_dev->caps.mtt_hop_num; 1926a93c77aSShaobo Xu break; 1936a93c77aSShaobo Xu case HEM_TYPE_CQE: 1946a93c77aSShaobo Xu mhop->buf_chunk_size = 1 << (hr_dev->caps.cqe_buf_pg_sz 1956a93c77aSShaobo Xu + PAGE_SHIFT); 1966a93c77aSShaobo Xu mhop->bt_chunk_size = 1 << (hr_dev->caps.cqe_ba_pg_sz 1976a93c77aSShaobo Xu + PAGE_SHIFT); 1982a3d923fSLijun Ou mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN; 1996a93c77aSShaobo Xu mhop->hop_num = hr_dev->caps.cqe_hop_num; 2006a93c77aSShaobo Xu break; 201c7bcb134SLijun Ou case HEM_TYPE_SRQWQE: 202c7bcb134SLijun Ou mhop->buf_chunk_size = 1 << (hr_dev->caps.srqwqe_buf_pg_sz 203c7bcb134SLijun Ou + PAGE_SHIFT); 204c7bcb134SLijun Ou mhop->bt_chunk_size = 1 << (hr_dev->caps.srqwqe_ba_pg_sz 205c7bcb134SLijun Ou + PAGE_SHIFT); 2062a3d923fSLijun Ou mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN; 207c7bcb134SLijun Ou mhop->hop_num = hr_dev->caps.srqwqe_hop_num; 208c7bcb134SLijun Ou break; 209c7bcb134SLijun Ou case HEM_TYPE_IDX: 210c7bcb134SLijun Ou mhop->buf_chunk_size = 1 << (hr_dev->caps.idx_buf_pg_sz 211c7bcb134SLijun Ou + PAGE_SHIFT); 212c7bcb134SLijun Ou mhop->bt_chunk_size = 1 << (hr_dev->caps.idx_ba_pg_sz 213c7bcb134SLijun Ou + PAGE_SHIFT); 2142a3d923fSLijun Ou mhop->ba_l0_num = mhop->bt_chunk_size / BA_BYTE_LEN; 215c7bcb134SLijun Ou mhop->hop_num = hr_dev->caps.idx_hop_num; 216c7bcb134SLijun Ou break; 217a25d13cbSShaobo Xu default: 218a25d13cbSShaobo Xu dev_err(dev, "Table %d not support multi-hop addressing!\n", 219*d7019c0fSLijun Ou type); 220a25d13cbSShaobo Xu return -EINVAL; 221a25d13cbSShaobo Xu } 222a25d13cbSShaobo Xu 223*d7019c0fSLijun Ou return 0; 224*d7019c0fSLijun Ou } 225*d7019c0fSLijun Ou 226*d7019c0fSLijun Ou int hns_roce_calc_hem_mhop(struct hns_roce_dev *hr_dev, 227*d7019c0fSLijun Ou struct hns_roce_hem_table *table, unsigned long *obj, 228*d7019c0fSLijun Ou struct hns_roce_hem_mhop *mhop) 229*d7019c0fSLijun Ou { 230*d7019c0fSLijun Ou struct device *dev = hr_dev->dev; 231*d7019c0fSLijun Ou u32 chunk_ba_num; 232*d7019c0fSLijun Ou u32 table_idx; 233*d7019c0fSLijun Ou u32 bt_num; 234*d7019c0fSLijun Ou u32 chunk_size; 235*d7019c0fSLijun Ou 236*d7019c0fSLijun Ou if (get_hem_table_config(hr_dev, mhop, table->type)) 237*d7019c0fSLijun Ou return -EINVAL; 238*d7019c0fSLijun Ou 239a25d13cbSShaobo Xu if (!obj) 240a25d13cbSShaobo Xu return 0; 241a25d13cbSShaobo Xu 2426a93c77aSShaobo Xu /* 2436a157f7dSYangyang Li * QPC/MTPT/CQC/SRQC/SCCC alloc hem for buffer pages. 2446a93c77aSShaobo Xu * MTT/CQE alloc hem for bt pages. 2456a93c77aSShaobo Xu */ 246a25d13cbSShaobo Xu bt_num = hns_roce_get_bt_num(table->type, mhop->hop_num); 2472a3d923fSLijun Ou chunk_ba_num = mhop->bt_chunk_size / BA_BYTE_LEN; 2486a93c77aSShaobo Xu chunk_size = table->type < HEM_TYPE_MTT ? mhop->buf_chunk_size : 2496a93c77aSShaobo Xu mhop->bt_chunk_size; 250a25d13cbSShaobo Xu table_idx = (*obj & (table->num_obj - 1)) / 251a25d13cbSShaobo Xu (chunk_size / table->obj_size); 252a25d13cbSShaobo Xu switch (bt_num) { 253a25d13cbSShaobo Xu case 3: 254a25d13cbSShaobo Xu mhop->l2_idx = table_idx & (chunk_ba_num - 1); 255a25d13cbSShaobo Xu mhop->l1_idx = table_idx / chunk_ba_num & (chunk_ba_num - 1); 25673b4e1f4SLijun Ou mhop->l0_idx = (table_idx / chunk_ba_num) / chunk_ba_num; 257a25d13cbSShaobo Xu break; 258a25d13cbSShaobo Xu case 2: 259a25d13cbSShaobo Xu mhop->l1_idx = table_idx & (chunk_ba_num - 1); 260a25d13cbSShaobo Xu mhop->l0_idx = table_idx / chunk_ba_num; 261a25d13cbSShaobo Xu break; 262a25d13cbSShaobo Xu case 1: 263a25d13cbSShaobo Xu mhop->l0_idx = table_idx; 264a25d13cbSShaobo Xu break; 265a25d13cbSShaobo Xu default: 266a25d13cbSShaobo Xu dev_err(dev, "Table %d not support hop_num = %d!\n", 267a25d13cbSShaobo Xu table->type, mhop->hop_num); 268a25d13cbSShaobo Xu return -EINVAL; 269a25d13cbSShaobo Xu } 270a25d13cbSShaobo Xu if (mhop->l0_idx >= mhop->ba_l0_num) 271a25d13cbSShaobo Xu mhop->l0_idx %= mhop->ba_l0_num; 272a25d13cbSShaobo Xu 273a25d13cbSShaobo Xu return 0; 274a25d13cbSShaobo Xu } 275a25d13cbSShaobo Xu 276a25d13cbSShaobo Xu static struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev, 277a25d13cbSShaobo Xu int npages, 278a25d13cbSShaobo Xu unsigned long hem_alloc_size, 2799a443537Soulijun gfp_t gfp_mask) 2809a443537Soulijun { 2819a443537Soulijun struct hns_roce_hem_chunk *chunk = NULL; 2829a443537Soulijun struct hns_roce_hem *hem; 2839a443537Soulijun struct scatterlist *mem; 2849a443537Soulijun int order; 2859a443537Soulijun void *buf; 2869a443537Soulijun 2879a443537Soulijun WARN_ON(gfp_mask & __GFP_HIGHMEM); 2889a443537Soulijun 2899a443537Soulijun hem = kmalloc(sizeof(*hem), 2909a443537Soulijun gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); 2919a443537Soulijun if (!hem) 2929a443537Soulijun return NULL; 2939a443537Soulijun 2949a443537Soulijun hem->refcount = 0; 2959a443537Soulijun INIT_LIST_HEAD(&hem->chunk_list); 2969a443537Soulijun 297a25d13cbSShaobo Xu order = get_order(hem_alloc_size); 2989a443537Soulijun 2999a443537Soulijun while (npages > 0) { 3009a443537Soulijun if (!chunk) { 3019a443537Soulijun chunk = kmalloc(sizeof(*chunk), 3029a443537Soulijun gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN)); 3039a443537Soulijun if (!chunk) 3049a443537Soulijun goto fail; 3059a443537Soulijun 3069a443537Soulijun sg_init_table(chunk->mem, HNS_ROCE_HEM_CHUNK_LEN); 3079a443537Soulijun chunk->npages = 0; 3089a443537Soulijun chunk->nsg = 0; 309378efe79SWei Hu\(Xavier\) memset(chunk->buf, 0, sizeof(chunk->buf)); 3109a443537Soulijun list_add_tail(&chunk->list, &hem->chunk_list); 3119a443537Soulijun } 3129a443537Soulijun 3139a443537Soulijun while (1 << order > npages) 3149a443537Soulijun --order; 3159a443537Soulijun 3169a443537Soulijun /* 3179a443537Soulijun * Alloc memory one time. If failed, don't alloc small block 3189a443537Soulijun * memory, directly return fail. 3199a443537Soulijun */ 3209a443537Soulijun mem = &chunk->mem[chunk->npages]; 32113ca970eSWei Hu(Xavier) buf = dma_alloc_coherent(hr_dev->dev, PAGE_SIZE << order, 3229a443537Soulijun &sg_dma_address(mem), gfp_mask); 3239a443537Soulijun if (!buf) 3249a443537Soulijun goto fail; 3259a443537Soulijun 326378efe79SWei Hu\(Xavier\) chunk->buf[chunk->npages] = buf; 3279a443537Soulijun sg_dma_len(mem) = PAGE_SIZE << order; 3289a443537Soulijun 3299a443537Soulijun ++chunk->npages; 3309a443537Soulijun ++chunk->nsg; 3319a443537Soulijun npages -= 1 << order; 3329a443537Soulijun } 3339a443537Soulijun 3349a443537Soulijun return hem; 3359a443537Soulijun 3369a443537Soulijun fail: 3379a443537Soulijun hns_roce_free_hem(hr_dev, hem); 3389a443537Soulijun return NULL; 3399a443537Soulijun } 3409a443537Soulijun 3419a443537Soulijun void hns_roce_free_hem(struct hns_roce_dev *hr_dev, struct hns_roce_hem *hem) 3429a443537Soulijun { 3439a443537Soulijun struct hns_roce_hem_chunk *chunk, *tmp; 3449a443537Soulijun int i; 3459a443537Soulijun 3469a443537Soulijun if (!hem) 3479a443537Soulijun return; 3489a443537Soulijun 3499a443537Soulijun list_for_each_entry_safe(chunk, tmp, &hem->chunk_list, list) { 3509a443537Soulijun for (i = 0; i < chunk->npages; ++i) 35113ca970eSWei Hu(Xavier) dma_free_coherent(hr_dev->dev, 352378efe79SWei Hu\(Xavier\) sg_dma_len(&chunk->mem[i]), 353378efe79SWei Hu\(Xavier\) chunk->buf[i], 3549a443537Soulijun sg_dma_address(&chunk->mem[i])); 3559a443537Soulijun kfree(chunk); 3569a443537Soulijun } 3579a443537Soulijun 3589a443537Soulijun kfree(hem); 3599a443537Soulijun } 3609a443537Soulijun 3619a443537Soulijun static int hns_roce_set_hem(struct hns_roce_dev *hr_dev, 3629a443537Soulijun struct hns_roce_hem_table *table, unsigned long obj) 3639a443537Soulijun { 3649a443537Soulijun spinlock_t *lock = &hr_dev->bt_cmd_lock; 36513ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev; 366a511f822SColin Ian King long end; 3679a443537Soulijun unsigned long flags; 3689a443537Soulijun struct hns_roce_hem_iter iter; 3699a443537Soulijun void __iomem *bt_cmd; 3709a443537Soulijun u32 bt_cmd_h_val = 0; 3719a443537Soulijun u32 bt_cmd_val[2]; 3729a443537Soulijun u32 bt_cmd_l = 0; 3739a443537Soulijun u64 bt_ba = 0; 3749a443537Soulijun int ret = 0; 3759a443537Soulijun 3769a443537Soulijun /* Find the HEM(Hardware Entry Memory) entry */ 3779a443537Soulijun unsigned long i = (obj & (table->num_obj - 1)) / 37829a1fe5dSWei Hu(Xavier) (table->table_chunk_size / table->obj_size); 3799a443537Soulijun 3809a443537Soulijun switch (table->type) { 3819a443537Soulijun case HEM_TYPE_QPC: 3829a443537Soulijun roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, 3839a443537Soulijun ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_QPC); 3849a443537Soulijun break; 3859a443537Soulijun case HEM_TYPE_MTPT: 3869a443537Soulijun roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, 3879a443537Soulijun ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, 3889a443537Soulijun HEM_TYPE_MTPT); 3899a443537Soulijun break; 3909a443537Soulijun case HEM_TYPE_CQC: 3919a443537Soulijun roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, 3929a443537Soulijun ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, HEM_TYPE_CQC); 3939a443537Soulijun break; 3949a443537Soulijun case HEM_TYPE_SRQC: 3959a443537Soulijun roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_M, 3969a443537Soulijun ROCEE_BT_CMD_H_ROCEE_BT_CMD_MDF_S, 3979a443537Soulijun HEM_TYPE_SRQC); 3989a443537Soulijun break; 3999a443537Soulijun default: 4009a443537Soulijun return ret; 4019a443537Soulijun } 4029a443537Soulijun roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_M, 4039a443537Soulijun ROCEE_BT_CMD_H_ROCEE_BT_CMD_IN_MDF_S, obj); 4049a443537Soulijun roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_S, 0); 4059a443537Soulijun roce_set_bit(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_HW_SYNS_S, 1); 4069a443537Soulijun 4079a443537Soulijun /* Currently iter only a chunk */ 4089a443537Soulijun for (hns_roce_hem_first(table->hem[i], &iter); 4099a443537Soulijun !hns_roce_hem_last(&iter); hns_roce_hem_next(&iter)) { 4109a443537Soulijun bt_ba = hns_roce_hem_addr(&iter) >> DMA_ADDR_T_SHIFT; 4119a443537Soulijun 4129a443537Soulijun spin_lock_irqsave(lock, flags); 4139a443537Soulijun 4149a443537Soulijun bt_cmd = hr_dev->reg_base + ROCEE_BT_CMD_H_REG; 4159a443537Soulijun 416669cefb6SLang Cheng end = HW_SYNC_TIMEOUT_MSECS; 417a511f822SColin Ian King while (end > 0) { 418fa027328SColin Ian King if (!(readl(bt_cmd) >> BT_CMD_SYNC_SHIFT)) 419669cefb6SLang Cheng break; 420669cefb6SLang Cheng 421669cefb6SLang Cheng mdelay(HW_SYNC_SLEEP_TIME_INTERVAL); 422669cefb6SLang Cheng end -= HW_SYNC_SLEEP_TIME_INTERVAL; 423669cefb6SLang Cheng } 424669cefb6SLang Cheng 425669cefb6SLang Cheng if (end <= 0) { 4269a443537Soulijun dev_err(dev, "Write bt_cmd err,hw_sync is not zero.\n"); 4279a443537Soulijun spin_unlock_irqrestore(lock, flags); 4289a443537Soulijun return -EBUSY; 4299a443537Soulijun } 4309a443537Soulijun 4319a443537Soulijun bt_cmd_l = (u32)bt_ba; 4329a443537Soulijun roce_set_field(bt_cmd_h_val, ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_M, 4339a443537Soulijun ROCEE_BT_CMD_H_ROCEE_BT_CMD_BA_H_S, 4349a443537Soulijun bt_ba >> BT_BA_SHIFT); 4359a443537Soulijun 4369a443537Soulijun bt_cmd_val[0] = bt_cmd_l; 4379a443537Soulijun bt_cmd_val[1] = bt_cmd_h_val; 4389a443537Soulijun hns_roce_write64_k(bt_cmd_val, 4399a443537Soulijun hr_dev->reg_base + ROCEE_BT_CMD_L_REG); 4409a443537Soulijun spin_unlock_irqrestore(lock, flags); 4419a443537Soulijun } 4429a443537Soulijun 4439a443537Soulijun return ret; 4449a443537Soulijun } 4459a443537Soulijun 446281d0ccfSColin Ian King static int hns_roce_table_mhop_get(struct hns_roce_dev *hr_dev, 447a25d13cbSShaobo Xu struct hns_roce_hem_table *table, 448a25d13cbSShaobo Xu unsigned long obj) 449a25d13cbSShaobo Xu { 450a25d13cbSShaobo Xu struct device *dev = hr_dev->dev; 451a25d13cbSShaobo Xu struct hns_roce_hem_mhop mhop; 452a25d13cbSShaobo Xu struct hns_roce_hem_iter iter; 453a25d13cbSShaobo Xu u32 buf_chunk_size; 454a25d13cbSShaobo Xu u32 bt_chunk_size; 455a25d13cbSShaobo Xu u32 chunk_ba_num; 456a25d13cbSShaobo Xu u32 hop_num; 457a25d13cbSShaobo Xu u32 size; 458a25d13cbSShaobo Xu u32 bt_num; 459a25d13cbSShaobo Xu u64 hem_idx; 460a25d13cbSShaobo Xu u64 bt_l1_idx = 0; 461a25d13cbSShaobo Xu u64 bt_l0_idx = 0; 462a25d13cbSShaobo Xu u64 bt_ba; 463a25d13cbSShaobo Xu unsigned long mhop_obj = obj; 464a25d13cbSShaobo Xu int bt_l1_allocated = 0; 465a25d13cbSShaobo Xu int bt_l0_allocated = 0; 466a25d13cbSShaobo Xu int step_idx; 467a25d13cbSShaobo Xu int ret; 468a25d13cbSShaobo Xu 469a25d13cbSShaobo Xu ret = hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, &mhop); 470a25d13cbSShaobo Xu if (ret) 471a25d13cbSShaobo Xu return ret; 472a25d13cbSShaobo Xu 473a25d13cbSShaobo Xu buf_chunk_size = mhop.buf_chunk_size; 474a25d13cbSShaobo Xu bt_chunk_size = mhop.bt_chunk_size; 475a25d13cbSShaobo Xu hop_num = mhop.hop_num; 4762a3d923fSLijun Ou chunk_ba_num = bt_chunk_size / BA_BYTE_LEN; 477a25d13cbSShaobo Xu 478a25d13cbSShaobo Xu bt_num = hns_roce_get_bt_num(table->type, hop_num); 479a25d13cbSShaobo Xu switch (bt_num) { 480a25d13cbSShaobo Xu case 3: 481a25d13cbSShaobo Xu hem_idx = mhop.l0_idx * chunk_ba_num * chunk_ba_num + 482a25d13cbSShaobo Xu mhop.l1_idx * chunk_ba_num + mhop.l2_idx; 483a25d13cbSShaobo Xu bt_l1_idx = mhop.l0_idx * chunk_ba_num + mhop.l1_idx; 484a25d13cbSShaobo Xu bt_l0_idx = mhop.l0_idx; 485a25d13cbSShaobo Xu break; 486a25d13cbSShaobo Xu case 2: 487a25d13cbSShaobo Xu hem_idx = mhop.l0_idx * chunk_ba_num + mhop.l1_idx; 488a25d13cbSShaobo Xu bt_l0_idx = mhop.l0_idx; 489a25d13cbSShaobo Xu break; 490a25d13cbSShaobo Xu case 1: 491a25d13cbSShaobo Xu hem_idx = mhop.l0_idx; 492a25d13cbSShaobo Xu break; 493a25d13cbSShaobo Xu default: 494a25d13cbSShaobo Xu dev_err(dev, "Table %d not support hop_num = %d!\n", 495a25d13cbSShaobo Xu table->type, hop_num); 496a25d13cbSShaobo Xu return -EINVAL; 497a25d13cbSShaobo Xu } 498a25d13cbSShaobo Xu 499a25d13cbSShaobo Xu mutex_lock(&table->mutex); 500a25d13cbSShaobo Xu 501a25d13cbSShaobo Xu if (table->hem[hem_idx]) { 502a25d13cbSShaobo Xu ++table->hem[hem_idx]->refcount; 503a25d13cbSShaobo Xu goto out; 504a25d13cbSShaobo Xu } 505a25d13cbSShaobo Xu 506a25d13cbSShaobo Xu /* alloc L1 BA's chunk */ 507a25d13cbSShaobo Xu if ((check_whether_bt_num_3(table->type, hop_num) || 508a25d13cbSShaobo Xu check_whether_bt_num_2(table->type, hop_num)) && 509a25d13cbSShaobo Xu !table->bt_l0[bt_l0_idx]) { 510a25d13cbSShaobo Xu table->bt_l0[bt_l0_idx] = dma_alloc_coherent(dev, bt_chunk_size, 511a25d13cbSShaobo Xu &(table->bt_l0_dma_addr[bt_l0_idx]), 512a25d13cbSShaobo Xu GFP_KERNEL); 513a25d13cbSShaobo Xu if (!table->bt_l0[bt_l0_idx]) { 514a25d13cbSShaobo Xu ret = -ENOMEM; 515a25d13cbSShaobo Xu goto out; 516a25d13cbSShaobo Xu } 517a25d13cbSShaobo Xu bt_l0_allocated = 1; 518a25d13cbSShaobo Xu 519a25d13cbSShaobo Xu /* set base address to hardware */ 520a25d13cbSShaobo Xu if (table->type < HEM_TYPE_MTT) { 521a25d13cbSShaobo Xu step_idx = 0; 522a25d13cbSShaobo Xu if (hr_dev->hw->set_hem(hr_dev, table, obj, step_idx)) { 523a25d13cbSShaobo Xu ret = -ENODEV; 524a25d13cbSShaobo Xu dev_err(dev, "set HEM base address to HW failed!\n"); 525a25d13cbSShaobo Xu goto err_dma_alloc_l1; 526a25d13cbSShaobo Xu } 527a25d13cbSShaobo Xu } 528a25d13cbSShaobo Xu } 529a25d13cbSShaobo Xu 530a25d13cbSShaobo Xu /* alloc L2 BA's chunk */ 531a25d13cbSShaobo Xu if (check_whether_bt_num_3(table->type, hop_num) && 532a25d13cbSShaobo Xu !table->bt_l1[bt_l1_idx]) { 533a25d13cbSShaobo Xu table->bt_l1[bt_l1_idx] = dma_alloc_coherent(dev, bt_chunk_size, 534a25d13cbSShaobo Xu &(table->bt_l1_dma_addr[bt_l1_idx]), 535a25d13cbSShaobo Xu GFP_KERNEL); 536a25d13cbSShaobo Xu if (!table->bt_l1[bt_l1_idx]) { 537a25d13cbSShaobo Xu ret = -ENOMEM; 538a25d13cbSShaobo Xu goto err_dma_alloc_l1; 539a25d13cbSShaobo Xu } 540a25d13cbSShaobo Xu bt_l1_allocated = 1; 541a25d13cbSShaobo Xu *(table->bt_l0[bt_l0_idx] + mhop.l1_idx) = 542a25d13cbSShaobo Xu table->bt_l1_dma_addr[bt_l1_idx]; 543a25d13cbSShaobo Xu 544a25d13cbSShaobo Xu /* set base address to hardware */ 545a25d13cbSShaobo Xu step_idx = 1; 546a25d13cbSShaobo Xu if (hr_dev->hw->set_hem(hr_dev, table, obj, step_idx)) { 547a25d13cbSShaobo Xu ret = -ENODEV; 548a25d13cbSShaobo Xu dev_err(dev, "set HEM base address to HW failed!\n"); 549a25d13cbSShaobo Xu goto err_alloc_hem_buf; 550a25d13cbSShaobo Xu } 551a25d13cbSShaobo Xu } 552a25d13cbSShaobo Xu 5536a93c77aSShaobo Xu /* 5546a157f7dSYangyang Li * alloc buffer space chunk for QPC/MTPT/CQC/SRQC/SCCC. 5556a93c77aSShaobo Xu * alloc bt space chunk for MTT/CQE. 5566a93c77aSShaobo Xu */ 5576a93c77aSShaobo Xu size = table->type < HEM_TYPE_MTT ? buf_chunk_size : bt_chunk_size; 558a25d13cbSShaobo Xu table->hem[hem_idx] = hns_roce_alloc_hem(hr_dev, 559a25d13cbSShaobo Xu size >> PAGE_SHIFT, 560a25d13cbSShaobo Xu size, 561a25d13cbSShaobo Xu (table->lowmem ? GFP_KERNEL : 562a25d13cbSShaobo Xu GFP_HIGHUSER) | __GFP_NOWARN); 563a25d13cbSShaobo Xu if (!table->hem[hem_idx]) { 564a25d13cbSShaobo Xu ret = -ENOMEM; 565a25d13cbSShaobo Xu goto err_alloc_hem_buf; 566a25d13cbSShaobo Xu } 567a25d13cbSShaobo Xu 568a25d13cbSShaobo Xu hns_roce_hem_first(table->hem[hem_idx], &iter); 569a25d13cbSShaobo Xu bt_ba = hns_roce_hem_addr(&iter); 570a25d13cbSShaobo Xu 571a25d13cbSShaobo Xu if (table->type < HEM_TYPE_MTT) { 572a25d13cbSShaobo Xu if (hop_num == 2) { 573a25d13cbSShaobo Xu *(table->bt_l1[bt_l1_idx] + mhop.l2_idx) = bt_ba; 574a25d13cbSShaobo Xu step_idx = 2; 575a25d13cbSShaobo Xu } else if (hop_num == 1) { 576a25d13cbSShaobo Xu *(table->bt_l0[bt_l0_idx] + mhop.l1_idx) = bt_ba; 577a25d13cbSShaobo Xu step_idx = 1; 578a25d13cbSShaobo Xu } else if (hop_num == HNS_ROCE_HOP_NUM_0) { 579a25d13cbSShaobo Xu step_idx = 0; 58026f63b9cSLijun Ou } else { 58126f63b9cSLijun Ou ret = -EINVAL; 58226f63b9cSLijun Ou goto err_dma_alloc_l1; 583a25d13cbSShaobo Xu } 584a25d13cbSShaobo Xu 585a25d13cbSShaobo Xu /* set HEM base address to hardware */ 586a25d13cbSShaobo Xu if (hr_dev->hw->set_hem(hr_dev, table, obj, step_idx)) { 587a25d13cbSShaobo Xu ret = -ENODEV; 588a25d13cbSShaobo Xu dev_err(dev, "set HEM base address to HW failed!\n"); 589a25d13cbSShaobo Xu goto err_alloc_hem_buf; 590a25d13cbSShaobo Xu } 5916a93c77aSShaobo Xu } else if (hop_num == 2) { 5926a93c77aSShaobo Xu *(table->bt_l0[bt_l0_idx] + mhop.l1_idx) = bt_ba; 593a25d13cbSShaobo Xu } 594a25d13cbSShaobo Xu 595a25d13cbSShaobo Xu ++table->hem[hem_idx]->refcount; 596a25d13cbSShaobo Xu goto out; 597a25d13cbSShaobo Xu 598a25d13cbSShaobo Xu err_alloc_hem_buf: 599a25d13cbSShaobo Xu if (bt_l1_allocated) { 600a25d13cbSShaobo Xu dma_free_coherent(dev, bt_chunk_size, table->bt_l1[bt_l1_idx], 601a25d13cbSShaobo Xu table->bt_l1_dma_addr[bt_l1_idx]); 602a25d13cbSShaobo Xu table->bt_l1[bt_l1_idx] = NULL; 603a25d13cbSShaobo Xu } 604a25d13cbSShaobo Xu 605a25d13cbSShaobo Xu err_dma_alloc_l1: 606a25d13cbSShaobo Xu if (bt_l0_allocated) { 607a25d13cbSShaobo Xu dma_free_coherent(dev, bt_chunk_size, table->bt_l0[bt_l0_idx], 608a25d13cbSShaobo Xu table->bt_l0_dma_addr[bt_l0_idx]); 609a25d13cbSShaobo Xu table->bt_l0[bt_l0_idx] = NULL; 610a25d13cbSShaobo Xu } 611a25d13cbSShaobo Xu 612a25d13cbSShaobo Xu out: 613a25d13cbSShaobo Xu mutex_unlock(&table->mutex); 614a25d13cbSShaobo Xu return ret; 615a25d13cbSShaobo Xu } 616a25d13cbSShaobo Xu 6179a443537Soulijun int hns_roce_table_get(struct hns_roce_dev *hr_dev, 6189a443537Soulijun struct hns_roce_hem_table *table, unsigned long obj) 6199a443537Soulijun { 62013ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev; 6219a443537Soulijun int ret = 0; 6229a443537Soulijun unsigned long i; 6239a443537Soulijun 624a25d13cbSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) 625a25d13cbSShaobo Xu return hns_roce_table_mhop_get(hr_dev, table, obj); 626a25d13cbSShaobo Xu 62729a1fe5dSWei Hu(Xavier) i = (obj & (table->num_obj - 1)) / (table->table_chunk_size / 6289a443537Soulijun table->obj_size); 6299a443537Soulijun 6309a443537Soulijun mutex_lock(&table->mutex); 6319a443537Soulijun 6329a443537Soulijun if (table->hem[i]) { 6339a443537Soulijun ++table->hem[i]->refcount; 6349a443537Soulijun goto out; 6359a443537Soulijun } 6369a443537Soulijun 6379a443537Soulijun table->hem[i] = hns_roce_alloc_hem(hr_dev, 63829a1fe5dSWei Hu(Xavier) table->table_chunk_size >> PAGE_SHIFT, 63929a1fe5dSWei Hu(Xavier) table->table_chunk_size, 6409a443537Soulijun (table->lowmem ? GFP_KERNEL : 6419a443537Soulijun GFP_HIGHUSER) | __GFP_NOWARN); 6429a443537Soulijun if (!table->hem[i]) { 6439a443537Soulijun ret = -ENOMEM; 6449a443537Soulijun goto out; 6459a443537Soulijun } 6469a443537Soulijun 6479a443537Soulijun /* Set HEM base address(128K/page, pa) to Hardware */ 6489a443537Soulijun if (hns_roce_set_hem(hr_dev, table, obj)) { 64908eb3018SWei Hu(Xavier) hns_roce_free_hem(hr_dev, table->hem[i]); 65008eb3018SWei Hu(Xavier) table->hem[i] = NULL; 6519a443537Soulijun ret = -ENODEV; 6529a443537Soulijun dev_err(dev, "set HEM base address to HW failed.\n"); 6539a443537Soulijun goto out; 6549a443537Soulijun } 6559a443537Soulijun 6569a443537Soulijun ++table->hem[i]->refcount; 6579a443537Soulijun out: 6589a443537Soulijun mutex_unlock(&table->mutex); 6599a443537Soulijun return ret; 6609a443537Soulijun } 6619a443537Soulijun 662281d0ccfSColin Ian King static void hns_roce_table_mhop_put(struct hns_roce_dev *hr_dev, 663a25d13cbSShaobo Xu struct hns_roce_hem_table *table, 664a25d13cbSShaobo Xu unsigned long obj, 665a25d13cbSShaobo Xu int check_refcount) 666a25d13cbSShaobo Xu { 667a25d13cbSShaobo Xu struct device *dev = hr_dev->dev; 668a25d13cbSShaobo Xu struct hns_roce_hem_mhop mhop; 669a25d13cbSShaobo Xu unsigned long mhop_obj = obj; 670a25d13cbSShaobo Xu u32 bt_chunk_size; 671a25d13cbSShaobo Xu u32 chunk_ba_num; 672a25d13cbSShaobo Xu u32 hop_num; 673a25d13cbSShaobo Xu u32 start_idx; 674a25d13cbSShaobo Xu u32 bt_num; 675a25d13cbSShaobo Xu u64 hem_idx; 676a25d13cbSShaobo Xu u64 bt_l1_idx = 0; 677a25d13cbSShaobo Xu int ret; 678a25d13cbSShaobo Xu 679a25d13cbSShaobo Xu ret = hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, &mhop); 680a25d13cbSShaobo Xu if (ret) 681a25d13cbSShaobo Xu return; 682a25d13cbSShaobo Xu 683a25d13cbSShaobo Xu bt_chunk_size = mhop.bt_chunk_size; 684a25d13cbSShaobo Xu hop_num = mhop.hop_num; 6852a3d923fSLijun Ou chunk_ba_num = bt_chunk_size / BA_BYTE_LEN; 686a25d13cbSShaobo Xu 687a25d13cbSShaobo Xu bt_num = hns_roce_get_bt_num(table->type, hop_num); 688a25d13cbSShaobo Xu switch (bt_num) { 689a25d13cbSShaobo Xu case 3: 690a25d13cbSShaobo Xu hem_idx = mhop.l0_idx * chunk_ba_num * chunk_ba_num + 691a25d13cbSShaobo Xu mhop.l1_idx * chunk_ba_num + mhop.l2_idx; 692a25d13cbSShaobo Xu bt_l1_idx = mhop.l0_idx * chunk_ba_num + mhop.l1_idx; 693a25d13cbSShaobo Xu break; 694a25d13cbSShaobo Xu case 2: 695a25d13cbSShaobo Xu hem_idx = mhop.l0_idx * chunk_ba_num + mhop.l1_idx; 696a25d13cbSShaobo Xu break; 697a25d13cbSShaobo Xu case 1: 698a25d13cbSShaobo Xu hem_idx = mhop.l0_idx; 699a25d13cbSShaobo Xu break; 700a25d13cbSShaobo Xu default: 701a25d13cbSShaobo Xu dev_err(dev, "Table %d not support hop_num = %d!\n", 702a25d13cbSShaobo Xu table->type, hop_num); 703a25d13cbSShaobo Xu return; 704a25d13cbSShaobo Xu } 705a25d13cbSShaobo Xu 706a25d13cbSShaobo Xu mutex_lock(&table->mutex); 707a25d13cbSShaobo Xu 708a25d13cbSShaobo Xu if (check_refcount && (--table->hem[hem_idx]->refcount > 0)) { 709a25d13cbSShaobo Xu mutex_unlock(&table->mutex); 710a25d13cbSShaobo Xu return; 711a25d13cbSShaobo Xu } 712a25d13cbSShaobo Xu 713a25d13cbSShaobo Xu if (table->type < HEM_TYPE_MTT && hop_num == 1) { 714a25d13cbSShaobo Xu if (hr_dev->hw->clear_hem(hr_dev, table, obj, 1)) 715a25d13cbSShaobo Xu dev_warn(dev, "Clear HEM base address failed.\n"); 716a25d13cbSShaobo Xu } else if (table->type < HEM_TYPE_MTT && hop_num == 2) { 717a25d13cbSShaobo Xu if (hr_dev->hw->clear_hem(hr_dev, table, obj, 2)) 718a25d13cbSShaobo Xu dev_warn(dev, "Clear HEM base address failed.\n"); 719a25d13cbSShaobo Xu } else if (table->type < HEM_TYPE_MTT && 720a25d13cbSShaobo Xu hop_num == HNS_ROCE_HOP_NUM_0) { 721a25d13cbSShaobo Xu if (hr_dev->hw->clear_hem(hr_dev, table, obj, 0)) 722a25d13cbSShaobo Xu dev_warn(dev, "Clear HEM base address failed.\n"); 723a25d13cbSShaobo Xu } 724a25d13cbSShaobo Xu 7256a93c77aSShaobo Xu /* 7266a157f7dSYangyang Li * free buffer space chunk for QPC/MTPT/CQC/SRQC/SCCC. 7276a93c77aSShaobo Xu * free bt space chunk for MTT/CQE. 7286a93c77aSShaobo Xu */ 729a25d13cbSShaobo Xu hns_roce_free_hem(hr_dev, table->hem[hem_idx]); 730a25d13cbSShaobo Xu table->hem[hem_idx] = NULL; 731a25d13cbSShaobo Xu 732a25d13cbSShaobo Xu if (check_whether_bt_num_2(table->type, hop_num)) { 733a25d13cbSShaobo Xu start_idx = mhop.l0_idx * chunk_ba_num; 734a25d13cbSShaobo Xu if (hns_roce_check_hem_null(table->hem, start_idx, 735a25d13cbSShaobo Xu chunk_ba_num)) { 736a25d13cbSShaobo Xu if (table->type < HEM_TYPE_MTT && 737a25d13cbSShaobo Xu hr_dev->hw->clear_hem(hr_dev, table, obj, 0)) 738a25d13cbSShaobo Xu dev_warn(dev, "Clear HEM base address failed.\n"); 739a25d13cbSShaobo Xu 740a25d13cbSShaobo Xu dma_free_coherent(dev, bt_chunk_size, 741a25d13cbSShaobo Xu table->bt_l0[mhop.l0_idx], 742a25d13cbSShaobo Xu table->bt_l0_dma_addr[mhop.l0_idx]); 743a25d13cbSShaobo Xu table->bt_l0[mhop.l0_idx] = NULL; 744a25d13cbSShaobo Xu } 745a25d13cbSShaobo Xu } else if (check_whether_bt_num_3(table->type, hop_num)) { 746a25d13cbSShaobo Xu start_idx = mhop.l0_idx * chunk_ba_num * chunk_ba_num + 747a25d13cbSShaobo Xu mhop.l1_idx * chunk_ba_num; 748a25d13cbSShaobo Xu if (hns_roce_check_hem_null(table->hem, start_idx, 749a25d13cbSShaobo Xu chunk_ba_num)) { 750a25d13cbSShaobo Xu if (hr_dev->hw->clear_hem(hr_dev, table, obj, 1)) 751a25d13cbSShaobo Xu dev_warn(dev, "Clear HEM base address failed.\n"); 752a25d13cbSShaobo Xu 753a25d13cbSShaobo Xu dma_free_coherent(dev, bt_chunk_size, 754a25d13cbSShaobo Xu table->bt_l1[bt_l1_idx], 755a25d13cbSShaobo Xu table->bt_l1_dma_addr[bt_l1_idx]); 756a25d13cbSShaobo Xu table->bt_l1[bt_l1_idx] = NULL; 757a25d13cbSShaobo Xu 758a25d13cbSShaobo Xu start_idx = mhop.l0_idx * chunk_ba_num; 759a25d13cbSShaobo Xu if (hns_roce_check_bt_null(table->bt_l1, start_idx, 760a25d13cbSShaobo Xu chunk_ba_num)) { 761a25d13cbSShaobo Xu if (hr_dev->hw->clear_hem(hr_dev, table, obj, 762a25d13cbSShaobo Xu 0)) 763a25d13cbSShaobo Xu dev_warn(dev, "Clear HEM base address failed.\n"); 764a25d13cbSShaobo Xu 765a25d13cbSShaobo Xu dma_free_coherent(dev, bt_chunk_size, 766a25d13cbSShaobo Xu table->bt_l0[mhop.l0_idx], 767a25d13cbSShaobo Xu table->bt_l0_dma_addr[mhop.l0_idx]); 768a25d13cbSShaobo Xu table->bt_l0[mhop.l0_idx] = NULL; 769a25d13cbSShaobo Xu } 770a25d13cbSShaobo Xu } 771a25d13cbSShaobo Xu } 772a25d13cbSShaobo Xu 773a25d13cbSShaobo Xu mutex_unlock(&table->mutex); 774a25d13cbSShaobo Xu } 775a25d13cbSShaobo Xu 7769a443537Soulijun void hns_roce_table_put(struct hns_roce_dev *hr_dev, 7779a443537Soulijun struct hns_roce_hem_table *table, unsigned long obj) 7789a443537Soulijun { 77913ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev; 7809a443537Soulijun unsigned long i; 7819a443537Soulijun 782a25d13cbSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) { 783a25d13cbSShaobo Xu hns_roce_table_mhop_put(hr_dev, table, obj, 1); 784a25d13cbSShaobo Xu return; 785a25d13cbSShaobo Xu } 786a25d13cbSShaobo Xu 7879a443537Soulijun i = (obj & (table->num_obj - 1)) / 78829a1fe5dSWei Hu(Xavier) (table->table_chunk_size / table->obj_size); 7899a443537Soulijun 7909a443537Soulijun mutex_lock(&table->mutex); 7919a443537Soulijun 7929a443537Soulijun if (--table->hem[i]->refcount == 0) { 7939a443537Soulijun /* Clear HEM base address */ 794a25d13cbSShaobo Xu if (hr_dev->hw->clear_hem(hr_dev, table, obj, 0)) 7959a443537Soulijun dev_warn(dev, "Clear HEM base address failed.\n"); 7969a443537Soulijun 7979a443537Soulijun hns_roce_free_hem(hr_dev, table->hem[i]); 7989a443537Soulijun table->hem[i] = NULL; 7999a443537Soulijun } 8009a443537Soulijun 8019a443537Soulijun mutex_unlock(&table->mutex); 8029a443537Soulijun } 8039a443537Soulijun 8046a93c77aSShaobo Xu void *hns_roce_table_find(struct hns_roce_dev *hr_dev, 8056a93c77aSShaobo Xu struct hns_roce_hem_table *table, 8066a93c77aSShaobo Xu unsigned long obj, dma_addr_t *dma_handle) 8079a443537Soulijun { 8089a443537Soulijun struct hns_roce_hem_chunk *chunk; 8096a93c77aSShaobo Xu struct hns_roce_hem_mhop mhop; 8109a443537Soulijun struct hns_roce_hem *hem; 811378efe79SWei Hu\(Xavier\) void *addr = NULL; 8126a93c77aSShaobo Xu unsigned long mhop_obj = obj; 8130203b14cSoulijun unsigned long obj_per_chunk; 8140203b14cSoulijun unsigned long idx_offset; 8156a93c77aSShaobo Xu int offset, dma_offset; 816378efe79SWei Hu\(Xavier\) int length; 8176a93c77aSShaobo Xu int i, j; 8186a93c77aSShaobo Xu u32 hem_idx = 0; 8199a443537Soulijun 8209a443537Soulijun if (!table->lowmem) 8219a443537Soulijun return NULL; 8229a443537Soulijun 8239a443537Soulijun mutex_lock(&table->mutex); 8246a93c77aSShaobo Xu 8256a93c77aSShaobo Xu if (!hns_roce_check_whether_mhop(hr_dev, table->type)) { 8260203b14cSoulijun obj_per_chunk = table->table_chunk_size / table->obj_size; 8270203b14cSoulijun hem = table->hem[(obj & (table->num_obj - 1)) / obj_per_chunk]; 8280203b14cSoulijun idx_offset = (obj & (table->num_obj - 1)) % obj_per_chunk; 8290203b14cSoulijun dma_offset = offset = idx_offset * table->obj_size; 8306a93c77aSShaobo Xu } else { 8314772e03dSLijun Ou u32 seg_size = 64; /* 8 bytes per BA and 8 BA per segment */ 8324772e03dSLijun Ou 8336a93c77aSShaobo Xu hns_roce_calc_hem_mhop(hr_dev, table, &mhop_obj, &mhop); 8346a93c77aSShaobo Xu /* mtt mhop */ 8356a93c77aSShaobo Xu i = mhop.l0_idx; 8366a93c77aSShaobo Xu j = mhop.l1_idx; 8376a93c77aSShaobo Xu if (mhop.hop_num == 2) 8382a3d923fSLijun Ou hem_idx = i * (mhop.bt_chunk_size / BA_BYTE_LEN) + j; 8396a93c77aSShaobo Xu else if (mhop.hop_num == 1 || 8406a93c77aSShaobo Xu mhop.hop_num == HNS_ROCE_HOP_NUM_0) 8416a93c77aSShaobo Xu hem_idx = i; 8426a93c77aSShaobo Xu 8436a93c77aSShaobo Xu hem = table->hem[hem_idx]; 8444772e03dSLijun Ou dma_offset = offset = (obj & (table->num_obj - 1)) * seg_size % 8454772e03dSLijun Ou mhop.bt_chunk_size; 8466a93c77aSShaobo Xu if (mhop.hop_num == 2) 8476a93c77aSShaobo Xu dma_offset = offset = 0; 8486a93c77aSShaobo Xu } 8499a443537Soulijun 8509a443537Soulijun if (!hem) 8519a443537Soulijun goto out; 8529a443537Soulijun 8539a443537Soulijun list_for_each_entry(chunk, &hem->chunk_list, list) { 8549a443537Soulijun for (i = 0; i < chunk->npages; ++i) { 855378efe79SWei Hu\(Xavier\) length = sg_dma_len(&chunk->mem[i]); 8569a443537Soulijun if (dma_handle && dma_offset >= 0) { 857378efe79SWei Hu\(Xavier\) if (length > (u32)dma_offset) 8589a443537Soulijun *dma_handle = sg_dma_address( 8599a443537Soulijun &chunk->mem[i]) + dma_offset; 860378efe79SWei Hu\(Xavier\) dma_offset -= length; 8619a443537Soulijun } 8629a443537Soulijun 863378efe79SWei Hu\(Xavier\) if (length > (u32)offset) { 864378efe79SWei Hu\(Xavier\) addr = chunk->buf[i] + offset; 8659a443537Soulijun goto out; 8669a443537Soulijun } 867378efe79SWei Hu\(Xavier\) offset -= length; 8689a443537Soulijun } 8699a443537Soulijun } 8709a443537Soulijun 8719a443537Soulijun out: 8729a443537Soulijun mutex_unlock(&table->mutex); 873378efe79SWei Hu\(Xavier\) return addr; 8749a443537Soulijun } 8759a443537Soulijun 8769a443537Soulijun int hns_roce_table_get_range(struct hns_roce_dev *hr_dev, 8779a443537Soulijun struct hns_roce_hem_table *table, 8789a443537Soulijun unsigned long start, unsigned long end) 8799a443537Soulijun { 8806a93c77aSShaobo Xu struct hns_roce_hem_mhop mhop; 88129a1fe5dSWei Hu(Xavier) unsigned long inc = table->table_chunk_size / table->obj_size; 8826a93c77aSShaobo Xu unsigned long i; 8836a93c77aSShaobo Xu int ret; 8846a93c77aSShaobo Xu 8856a93c77aSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) { 8866a93c77aSShaobo Xu hns_roce_calc_hem_mhop(hr_dev, table, NULL, &mhop); 8876a93c77aSShaobo Xu inc = mhop.bt_chunk_size / table->obj_size; 8886a93c77aSShaobo Xu } 8899a443537Soulijun 8909a443537Soulijun /* Allocate MTT entry memory according to chunk(128K) */ 8919a443537Soulijun for (i = start; i <= end; i += inc) { 8929a443537Soulijun ret = hns_roce_table_get(hr_dev, table, i); 8939a443537Soulijun if (ret) 8949a443537Soulijun goto fail; 8959a443537Soulijun } 8969a443537Soulijun 8979a443537Soulijun return 0; 8989a443537Soulijun 8999a443537Soulijun fail: 9009a443537Soulijun while (i > start) { 9019a443537Soulijun i -= inc; 9029a443537Soulijun hns_roce_table_put(hr_dev, table, i); 9039a443537Soulijun } 9049a443537Soulijun return ret; 9059a443537Soulijun } 9069a443537Soulijun 9079a443537Soulijun void hns_roce_table_put_range(struct hns_roce_dev *hr_dev, 9089a443537Soulijun struct hns_roce_hem_table *table, 9099a443537Soulijun unsigned long start, unsigned long end) 9109a443537Soulijun { 9116a93c77aSShaobo Xu struct hns_roce_hem_mhop mhop; 91229a1fe5dSWei Hu(Xavier) unsigned long inc = table->table_chunk_size / table->obj_size; 9139a443537Soulijun unsigned long i; 9149a443537Soulijun 9156a93c77aSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) { 9166a93c77aSShaobo Xu hns_roce_calc_hem_mhop(hr_dev, table, NULL, &mhop); 9176a93c77aSShaobo Xu inc = mhop.bt_chunk_size / table->obj_size; 9186a93c77aSShaobo Xu } 9196a93c77aSShaobo Xu 92029a1fe5dSWei Hu(Xavier) for (i = start; i <= end; i += inc) 9219a443537Soulijun hns_roce_table_put(hr_dev, table, i); 9229a443537Soulijun } 9239a443537Soulijun 9249a443537Soulijun int hns_roce_init_hem_table(struct hns_roce_dev *hr_dev, 9259a443537Soulijun struct hns_roce_hem_table *table, u32 type, 9269a443537Soulijun unsigned long obj_size, unsigned long nobj, 9279a443537Soulijun int use_lowmem) 9289a443537Soulijun { 9299a443537Soulijun unsigned long obj_per_chunk; 9309a443537Soulijun unsigned long num_hem; 9319a443537Soulijun 932a25d13cbSShaobo Xu if (!hns_roce_check_whether_mhop(hr_dev, type)) { 93329a1fe5dSWei Hu(Xavier) table->table_chunk_size = hr_dev->caps.chunk_sz; 93429a1fe5dSWei Hu(Xavier) obj_per_chunk = table->table_chunk_size / obj_size; 9359a443537Soulijun num_hem = (nobj + obj_per_chunk - 1) / obj_per_chunk; 9369a443537Soulijun 9379a443537Soulijun table->hem = kcalloc(num_hem, sizeof(*table->hem), GFP_KERNEL); 9389a443537Soulijun if (!table->hem) 9399a443537Soulijun return -ENOMEM; 940a25d13cbSShaobo Xu } else { 941*d7019c0fSLijun Ou struct hns_roce_hem_mhop mhop = {}; 942a25d13cbSShaobo Xu unsigned long buf_chunk_size; 943a25d13cbSShaobo Xu unsigned long bt_chunk_size; 944a25d13cbSShaobo Xu unsigned long bt_chunk_num; 9456a93c77aSShaobo Xu unsigned long num_bt_l0 = 0; 946a25d13cbSShaobo Xu u32 hop_num; 947a25d13cbSShaobo Xu 948*d7019c0fSLijun Ou if (get_hem_table_config(hr_dev, &mhop, type)) 949a25d13cbSShaobo Xu return -EINVAL; 950*d7019c0fSLijun Ou 951*d7019c0fSLijun Ou buf_chunk_size = mhop.buf_chunk_size; 952*d7019c0fSLijun Ou bt_chunk_size = mhop.bt_chunk_size; 953*d7019c0fSLijun Ou num_bt_l0 = mhop.ba_l0_num; 954*d7019c0fSLijun Ou hop_num = mhop.hop_num; 955*d7019c0fSLijun Ou 956a25d13cbSShaobo Xu obj_per_chunk = buf_chunk_size / obj_size; 957a25d13cbSShaobo Xu num_hem = (nobj + obj_per_chunk - 1) / obj_per_chunk; 9582a3d923fSLijun Ou bt_chunk_num = bt_chunk_size / BA_BYTE_LEN; 959215a8c09Soulijun if (type >= HEM_TYPE_MTT) 9606a93c77aSShaobo Xu num_bt_l0 = bt_chunk_num; 961a25d13cbSShaobo Xu 962a25d13cbSShaobo Xu table->hem = kcalloc(num_hem, sizeof(*table->hem), 963a25d13cbSShaobo Xu GFP_KERNEL); 964a25d13cbSShaobo Xu if (!table->hem) 965a25d13cbSShaobo Xu goto err_kcalloc_hem_buf; 966a25d13cbSShaobo Xu 967215a8c09Soulijun if (check_whether_bt_num_3(type, hop_num)) { 968a25d13cbSShaobo Xu unsigned long num_bt_l1; 969a25d13cbSShaobo Xu 970a25d13cbSShaobo Xu num_bt_l1 = (num_hem + bt_chunk_num - 1) / 971a25d13cbSShaobo Xu bt_chunk_num; 972a25d13cbSShaobo Xu table->bt_l1 = kcalloc(num_bt_l1, 973a25d13cbSShaobo Xu sizeof(*table->bt_l1), 974a25d13cbSShaobo Xu GFP_KERNEL); 975a25d13cbSShaobo Xu if (!table->bt_l1) 976a25d13cbSShaobo Xu goto err_kcalloc_bt_l1; 977a25d13cbSShaobo Xu 978a25d13cbSShaobo Xu table->bt_l1_dma_addr = kcalloc(num_bt_l1, 979a25d13cbSShaobo Xu sizeof(*table->bt_l1_dma_addr), 980a25d13cbSShaobo Xu GFP_KERNEL); 981a25d13cbSShaobo Xu 982a25d13cbSShaobo Xu if (!table->bt_l1_dma_addr) 983a25d13cbSShaobo Xu goto err_kcalloc_l1_dma; 984a25d13cbSShaobo Xu } 985a25d13cbSShaobo Xu 986215a8c09Soulijun if (check_whether_bt_num_2(type, hop_num) || 987215a8c09Soulijun check_whether_bt_num_3(type, hop_num)) { 988a25d13cbSShaobo Xu table->bt_l0 = kcalloc(num_bt_l0, sizeof(*table->bt_l0), 989a25d13cbSShaobo Xu GFP_KERNEL); 990a25d13cbSShaobo Xu if (!table->bt_l0) 991a25d13cbSShaobo Xu goto err_kcalloc_bt_l0; 992a25d13cbSShaobo Xu 993a25d13cbSShaobo Xu table->bt_l0_dma_addr = kcalloc(num_bt_l0, 994a25d13cbSShaobo Xu sizeof(*table->bt_l0_dma_addr), 995a25d13cbSShaobo Xu GFP_KERNEL); 996a25d13cbSShaobo Xu if (!table->bt_l0_dma_addr) 997a25d13cbSShaobo Xu goto err_kcalloc_l0_dma; 998a25d13cbSShaobo Xu } 999a25d13cbSShaobo Xu } 10009a443537Soulijun 10019a443537Soulijun table->type = type; 10029a443537Soulijun table->num_hem = num_hem; 10039a443537Soulijun table->num_obj = nobj; 10049a443537Soulijun table->obj_size = obj_size; 10059a443537Soulijun table->lowmem = use_lowmem; 10069a443537Soulijun mutex_init(&table->mutex); 10079a443537Soulijun 10089a443537Soulijun return 0; 1009a25d13cbSShaobo Xu 1010a25d13cbSShaobo Xu err_kcalloc_l0_dma: 1011a25d13cbSShaobo Xu kfree(table->bt_l0); 1012a25d13cbSShaobo Xu table->bt_l0 = NULL; 1013a25d13cbSShaobo Xu 1014a25d13cbSShaobo Xu err_kcalloc_bt_l0: 1015a25d13cbSShaobo Xu kfree(table->bt_l1_dma_addr); 1016a25d13cbSShaobo Xu table->bt_l1_dma_addr = NULL; 1017a25d13cbSShaobo Xu 1018a25d13cbSShaobo Xu err_kcalloc_l1_dma: 1019a25d13cbSShaobo Xu kfree(table->bt_l1); 1020a25d13cbSShaobo Xu table->bt_l1 = NULL; 1021a25d13cbSShaobo Xu 1022a25d13cbSShaobo Xu err_kcalloc_bt_l1: 1023a25d13cbSShaobo Xu kfree(table->hem); 1024a25d13cbSShaobo Xu table->hem = NULL; 1025a25d13cbSShaobo Xu 1026a25d13cbSShaobo Xu err_kcalloc_hem_buf: 1027a25d13cbSShaobo Xu return -ENOMEM; 1028a25d13cbSShaobo Xu } 1029a25d13cbSShaobo Xu 1030281d0ccfSColin Ian King static void hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev *hr_dev, 1031a25d13cbSShaobo Xu struct hns_roce_hem_table *table) 1032a25d13cbSShaobo Xu { 1033a25d13cbSShaobo Xu struct hns_roce_hem_mhop mhop; 1034a25d13cbSShaobo Xu u32 buf_chunk_size; 1035a25d13cbSShaobo Xu int i; 1036a25d13cbSShaobo Xu u64 obj; 1037a25d13cbSShaobo Xu 1038a25d13cbSShaobo Xu hns_roce_calc_hem_mhop(hr_dev, table, NULL, &mhop); 10396a93c77aSShaobo Xu buf_chunk_size = table->type < HEM_TYPE_MTT ? mhop.buf_chunk_size : 10406a93c77aSShaobo Xu mhop.bt_chunk_size; 1041a25d13cbSShaobo Xu 1042a25d13cbSShaobo Xu for (i = 0; i < table->num_hem; ++i) { 1043a25d13cbSShaobo Xu obj = i * buf_chunk_size / table->obj_size; 1044a25d13cbSShaobo Xu if (table->hem[i]) 1045a25d13cbSShaobo Xu hns_roce_table_mhop_put(hr_dev, table, obj, 0); 1046a25d13cbSShaobo Xu } 1047a25d13cbSShaobo Xu 1048a25d13cbSShaobo Xu kfree(table->hem); 1049a25d13cbSShaobo Xu table->hem = NULL; 1050a25d13cbSShaobo Xu kfree(table->bt_l1); 1051a25d13cbSShaobo Xu table->bt_l1 = NULL; 1052a25d13cbSShaobo Xu kfree(table->bt_l1_dma_addr); 1053a25d13cbSShaobo Xu table->bt_l1_dma_addr = NULL; 1054a25d13cbSShaobo Xu kfree(table->bt_l0); 1055a25d13cbSShaobo Xu table->bt_l0 = NULL; 1056a25d13cbSShaobo Xu kfree(table->bt_l0_dma_addr); 1057a25d13cbSShaobo Xu table->bt_l0_dma_addr = NULL; 10589a443537Soulijun } 10599a443537Soulijun 10609a443537Soulijun void hns_roce_cleanup_hem_table(struct hns_roce_dev *hr_dev, 10619a443537Soulijun struct hns_roce_hem_table *table) 10629a443537Soulijun { 106313ca970eSWei Hu(Xavier) struct device *dev = hr_dev->dev; 10649a443537Soulijun unsigned long i; 10659a443537Soulijun 1066a25d13cbSShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, table->type)) { 1067a25d13cbSShaobo Xu hns_roce_cleanup_mhop_hem_table(hr_dev, table); 1068a25d13cbSShaobo Xu return; 1069a25d13cbSShaobo Xu } 1070a25d13cbSShaobo Xu 10719a443537Soulijun for (i = 0; i < table->num_hem; ++i) 10729a443537Soulijun if (table->hem[i]) { 107397f0e39fSWei Hu (Xavier) if (hr_dev->hw->clear_hem(hr_dev, table, 107429a1fe5dSWei Hu(Xavier) i * table->table_chunk_size / table->obj_size, 0)) 10759a443537Soulijun dev_err(dev, "Clear HEM base address failed.\n"); 10769a443537Soulijun 10779a443537Soulijun hns_roce_free_hem(hr_dev, table->hem[i]); 10789a443537Soulijun } 10799a443537Soulijun 10809a443537Soulijun kfree(table->hem); 10819a443537Soulijun } 10829a443537Soulijun 10839a443537Soulijun void hns_roce_cleanup_hem(struct hns_roce_dev *hr_dev) 10849a443537Soulijun { 10855c1f167aSLijun Ou if ((hr_dev->caps.num_idx_segs)) 10865c1f167aSLijun Ou hns_roce_cleanup_hem_table(hr_dev, 10875c1f167aSLijun Ou &hr_dev->mr_table.mtt_idx_table); 10885c1f167aSLijun Ou if (hr_dev->caps.num_srqwqe_segs) 10895c1f167aSLijun Ou hns_roce_cleanup_hem_table(hr_dev, 10905c1f167aSLijun Ou &hr_dev->mr_table.mtt_srqwqe_table); 10915c1f167aSLijun Ou if (hr_dev->caps.srqc_entry_sz) 10925c1f167aSLijun Ou hns_roce_cleanup_hem_table(hr_dev, 10935c1f167aSLijun Ou &hr_dev->srq_table.table); 10949a443537Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->cq_table.table); 10950e40dc2fSYangyang Li if (hr_dev->caps.qpc_timer_entry_sz) 10960e40dc2fSYangyang Li hns_roce_cleanup_hem_table(hr_dev, 10970e40dc2fSYangyang Li &hr_dev->qpc_timer_table); 10980e40dc2fSYangyang Li if (hr_dev->caps.cqc_timer_entry_sz) 10990e40dc2fSYangyang Li hns_roce_cleanup_hem_table(hr_dev, 11000e40dc2fSYangyang Li &hr_dev->cqc_timer_table); 11016a157f7dSYangyang Li if (hr_dev->caps.sccc_entry_sz) 11026a157f7dSYangyang Li hns_roce_cleanup_hem_table(hr_dev, 11036a157f7dSYangyang Li &hr_dev->qp_table.sccc_table); 1104e92f2c18Soulijun if (hr_dev->caps.trrl_entry_sz) 1105e92f2c18Soulijun hns_roce_cleanup_hem_table(hr_dev, 1106e92f2c18Soulijun &hr_dev->qp_table.trrl_table); 1107ae25db00Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.irrl_table); 11089a443537Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->qp_table.qp_table); 11099a443537Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtpt_table); 11109766edc3SShaobo Xu if (hns_roce_check_whether_mhop(hr_dev, HEM_TYPE_CQE)) 11119766edc3SShaobo Xu hns_roce_cleanup_hem_table(hr_dev, 11129766edc3SShaobo Xu &hr_dev->mr_table.mtt_cqe_table); 1113ae25db00Soulijun hns_roce_cleanup_hem_table(hr_dev, &hr_dev->mr_table.mtt_table); 11149a443537Soulijun } 111538389eaaSLijun Ou 111638389eaaSLijun Ou struct roce_hem_item { 111738389eaaSLijun Ou struct list_head list; /* link all hems in the same bt level */ 111838389eaaSLijun Ou struct list_head sibling; /* link all hems in last hop for mtt */ 111938389eaaSLijun Ou void *addr; 112038389eaaSLijun Ou dma_addr_t dma_addr; 112138389eaaSLijun Ou size_t count; /* max ba numbers */ 112238389eaaSLijun Ou int start; /* start buf offset in this hem */ 112338389eaaSLijun Ou int end; /* end buf offset in this hem */ 112438389eaaSLijun Ou }; 112538389eaaSLijun Ou 112638389eaaSLijun Ou static struct roce_hem_item *hem_list_alloc_item(struct hns_roce_dev *hr_dev, 112738389eaaSLijun Ou int start, int end, 112838389eaaSLijun Ou int count, bool exist_bt, 112938389eaaSLijun Ou int bt_level) 113038389eaaSLijun Ou { 113138389eaaSLijun Ou struct roce_hem_item *hem; 113238389eaaSLijun Ou 113338389eaaSLijun Ou hem = kzalloc(sizeof(*hem), GFP_KERNEL); 113438389eaaSLijun Ou if (!hem) 113538389eaaSLijun Ou return NULL; 113638389eaaSLijun Ou 113738389eaaSLijun Ou if (exist_bt) { 113838389eaaSLijun Ou hem->addr = dma_alloc_coherent(hr_dev->dev, 113938389eaaSLijun Ou count * BA_BYTE_LEN, 114038389eaaSLijun Ou &hem->dma_addr, GFP_KERNEL); 114138389eaaSLijun Ou if (!hem->addr) { 114238389eaaSLijun Ou kfree(hem); 114338389eaaSLijun Ou return NULL; 114438389eaaSLijun Ou } 114538389eaaSLijun Ou } 114638389eaaSLijun Ou 114738389eaaSLijun Ou hem->count = count; 114838389eaaSLijun Ou hem->start = start; 114938389eaaSLijun Ou hem->end = end; 115038389eaaSLijun Ou INIT_LIST_HEAD(&hem->list); 115138389eaaSLijun Ou INIT_LIST_HEAD(&hem->sibling); 115238389eaaSLijun Ou 115338389eaaSLijun Ou return hem; 115438389eaaSLijun Ou } 115538389eaaSLijun Ou 115638389eaaSLijun Ou static void hem_list_free_item(struct hns_roce_dev *hr_dev, 115738389eaaSLijun Ou struct roce_hem_item *hem, bool exist_bt) 115838389eaaSLijun Ou { 115938389eaaSLijun Ou if (exist_bt) 116038389eaaSLijun Ou dma_free_coherent(hr_dev->dev, hem->count * BA_BYTE_LEN, 116138389eaaSLijun Ou hem->addr, hem->dma_addr); 116238389eaaSLijun Ou kfree(hem); 116338389eaaSLijun Ou } 116438389eaaSLijun Ou 116538389eaaSLijun Ou static void hem_list_free_all(struct hns_roce_dev *hr_dev, 116638389eaaSLijun Ou struct list_head *head, bool exist_bt) 116738389eaaSLijun Ou { 116838389eaaSLijun Ou struct roce_hem_item *hem, *temp_hem; 116938389eaaSLijun Ou 117038389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, head, list) { 117138389eaaSLijun Ou list_del(&hem->list); 117238389eaaSLijun Ou hem_list_free_item(hr_dev, hem, exist_bt); 117338389eaaSLijun Ou } 117438389eaaSLijun Ou } 117538389eaaSLijun Ou 117638389eaaSLijun Ou static void hem_list_link_bt(struct hns_roce_dev *hr_dev, void *base_addr, 117738389eaaSLijun Ou u64 table_addr) 117838389eaaSLijun Ou { 117938389eaaSLijun Ou *(u64 *)(base_addr) = table_addr; 118038389eaaSLijun Ou } 118138389eaaSLijun Ou 118238389eaaSLijun Ou /* assign L0 table address to hem from root bt */ 118338389eaaSLijun Ou static void hem_list_assign_bt(struct hns_roce_dev *hr_dev, 118438389eaaSLijun Ou struct roce_hem_item *hem, void *cpu_addr, 118538389eaaSLijun Ou u64 phy_addr) 118638389eaaSLijun Ou { 118738389eaaSLijun Ou hem->addr = cpu_addr; 118838389eaaSLijun Ou hem->dma_addr = (dma_addr_t)phy_addr; 118938389eaaSLijun Ou } 119038389eaaSLijun Ou 119138389eaaSLijun Ou static inline bool hem_list_page_is_in_range(struct roce_hem_item *hem, 119238389eaaSLijun Ou int offset) 119338389eaaSLijun Ou { 119438389eaaSLijun Ou return (hem->start <= offset && offset <= hem->end); 119538389eaaSLijun Ou } 119638389eaaSLijun Ou 119738389eaaSLijun Ou static struct roce_hem_item *hem_list_search_item(struct list_head *ba_list, 119838389eaaSLijun Ou int page_offset) 119938389eaaSLijun Ou { 120038389eaaSLijun Ou struct roce_hem_item *hem, *temp_hem; 120138389eaaSLijun Ou struct roce_hem_item *found = NULL; 120238389eaaSLijun Ou 120338389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, ba_list, list) { 120438389eaaSLijun Ou if (hem_list_page_is_in_range(hem, page_offset)) { 120538389eaaSLijun Ou found = hem; 120638389eaaSLijun Ou break; 120738389eaaSLijun Ou } 120838389eaaSLijun Ou } 120938389eaaSLijun Ou 121038389eaaSLijun Ou return found; 121138389eaaSLijun Ou } 121238389eaaSLijun Ou 121338389eaaSLijun Ou static bool hem_list_is_bottom_bt(int hopnum, int bt_level) 121438389eaaSLijun Ou { 121538389eaaSLijun Ou /* 121638389eaaSLijun Ou * hopnum base address table levels 121738389eaaSLijun Ou * 0 L0(buf) 121838389eaaSLijun Ou * 1 L0 -> buf 121938389eaaSLijun Ou * 2 L0 -> L1 -> buf 122038389eaaSLijun Ou * 3 L0 -> L1 -> L2 -> buf 122138389eaaSLijun Ou */ 122238389eaaSLijun Ou return bt_level >= (hopnum ? hopnum - 1 : hopnum); 122338389eaaSLijun Ou } 122438389eaaSLijun Ou 122538389eaaSLijun Ou /** 122638389eaaSLijun Ou * calc base address entries num 122738389eaaSLijun Ou * @hopnum: num of mutihop addressing 122838389eaaSLijun Ou * @bt_level: base address table level 122938389eaaSLijun Ou * @unit: ba entries per bt page 123038389eaaSLijun Ou */ 123138389eaaSLijun Ou static u32 hem_list_calc_ba_range(int hopnum, int bt_level, int unit) 123238389eaaSLijun Ou { 123338389eaaSLijun Ou u32 step; 123438389eaaSLijun Ou int max; 123538389eaaSLijun Ou int i; 123638389eaaSLijun Ou 123738389eaaSLijun Ou if (hopnum <= bt_level) 123838389eaaSLijun Ou return 0; 123938389eaaSLijun Ou /* 124038389eaaSLijun Ou * hopnum bt_level range 124138389eaaSLijun Ou * 1 0 unit 124238389eaaSLijun Ou * ------------ 124338389eaaSLijun Ou * 2 0 unit * unit 124438389eaaSLijun Ou * 2 1 unit 124538389eaaSLijun Ou * ------------ 124638389eaaSLijun Ou * 3 0 unit * unit * unit 124738389eaaSLijun Ou * 3 1 unit * unit 124838389eaaSLijun Ou * 3 2 unit 124938389eaaSLijun Ou */ 125038389eaaSLijun Ou step = 1; 125138389eaaSLijun Ou max = hopnum - bt_level; 125238389eaaSLijun Ou for (i = 0; i < max; i++) 125338389eaaSLijun Ou step = step * unit; 125438389eaaSLijun Ou 125538389eaaSLijun Ou return step; 125638389eaaSLijun Ou } 125738389eaaSLijun Ou 125838389eaaSLijun Ou /** 125938389eaaSLijun Ou * calc the root ba entries which could cover all regions 126038389eaaSLijun Ou * @regions: buf region array 126138389eaaSLijun Ou * @region_cnt: array size of @regions 126238389eaaSLijun Ou * @unit: ba entries per bt page 126338389eaaSLijun Ou */ 126438389eaaSLijun Ou int hns_roce_hem_list_calc_root_ba(const struct hns_roce_buf_region *regions, 126538389eaaSLijun Ou int region_cnt, int unit) 126638389eaaSLijun Ou { 126738389eaaSLijun Ou struct hns_roce_buf_region *r; 126838389eaaSLijun Ou int total = 0; 126938389eaaSLijun Ou int step; 127038389eaaSLijun Ou int i; 127138389eaaSLijun Ou 127238389eaaSLijun Ou for (i = 0; i < region_cnt; i++) { 127338389eaaSLijun Ou r = (struct hns_roce_buf_region *)®ions[i]; 127438389eaaSLijun Ou if (r->hopnum > 1) { 127538389eaaSLijun Ou step = hem_list_calc_ba_range(r->hopnum, 1, unit); 127638389eaaSLijun Ou if (step > 0) 127738389eaaSLijun Ou total += (r->count + step - 1) / step; 127838389eaaSLijun Ou } else { 127938389eaaSLijun Ou total += r->count; 128038389eaaSLijun Ou } 128138389eaaSLijun Ou } 128238389eaaSLijun Ou 128338389eaaSLijun Ou return total; 128438389eaaSLijun Ou } 128538389eaaSLijun Ou 128638389eaaSLijun Ou static int hem_list_alloc_mid_bt(struct hns_roce_dev *hr_dev, 128738389eaaSLijun Ou const struct hns_roce_buf_region *r, int unit, 128838389eaaSLijun Ou int offset, struct list_head *mid_bt, 128938389eaaSLijun Ou struct list_head *btm_bt) 129038389eaaSLijun Ou { 129138389eaaSLijun Ou struct roce_hem_item *hem_ptrs[HNS_ROCE_MAX_BT_LEVEL] = { NULL }; 129238389eaaSLijun Ou struct list_head temp_list[HNS_ROCE_MAX_BT_LEVEL]; 129338389eaaSLijun Ou struct roce_hem_item *cur, *pre; 129438389eaaSLijun Ou const int hopnum = r->hopnum; 129538389eaaSLijun Ou int start_aligned; 129638389eaaSLijun Ou int distance; 129738389eaaSLijun Ou int ret = 0; 129838389eaaSLijun Ou int max_ofs; 129938389eaaSLijun Ou int level; 130038389eaaSLijun Ou u32 step; 130138389eaaSLijun Ou int end; 130238389eaaSLijun Ou 130338389eaaSLijun Ou if (hopnum <= 1) 130438389eaaSLijun Ou return 0; 130538389eaaSLijun Ou 130638389eaaSLijun Ou if (hopnum > HNS_ROCE_MAX_BT_LEVEL) { 130738389eaaSLijun Ou dev_err(hr_dev->dev, "invalid hopnum %d!\n", hopnum); 130838389eaaSLijun Ou return -EINVAL; 130938389eaaSLijun Ou } 131038389eaaSLijun Ou 131138389eaaSLijun Ou if (offset < r->offset) { 131238389eaaSLijun Ou dev_err(hr_dev->dev, "invalid offset %d,min %d!\n", 131338389eaaSLijun Ou offset, r->offset); 131438389eaaSLijun Ou return -EINVAL; 131538389eaaSLijun Ou } 131638389eaaSLijun Ou 131738389eaaSLijun Ou distance = offset - r->offset; 131838389eaaSLijun Ou max_ofs = r->offset + r->count - 1; 131938389eaaSLijun Ou for (level = 0; level < hopnum; level++) 132038389eaaSLijun Ou INIT_LIST_HEAD(&temp_list[level]); 132138389eaaSLijun Ou 132238389eaaSLijun Ou /* config L1 bt to last bt and link them to corresponding parent */ 132338389eaaSLijun Ou for (level = 1; level < hopnum; level++) { 132438389eaaSLijun Ou cur = hem_list_search_item(&mid_bt[level], offset); 132538389eaaSLijun Ou if (cur) { 132638389eaaSLijun Ou hem_ptrs[level] = cur; 132738389eaaSLijun Ou continue; 132838389eaaSLijun Ou } 132938389eaaSLijun Ou 133038389eaaSLijun Ou step = hem_list_calc_ba_range(hopnum, level, unit); 133138389eaaSLijun Ou if (step < 1) { 133238389eaaSLijun Ou ret = -EINVAL; 133338389eaaSLijun Ou goto err_exit; 133438389eaaSLijun Ou } 133538389eaaSLijun Ou 133638389eaaSLijun Ou start_aligned = (distance / step) * step + r->offset; 133738389eaaSLijun Ou end = min_t(int, start_aligned + step - 1, max_ofs); 133838389eaaSLijun Ou cur = hem_list_alloc_item(hr_dev, start_aligned, end, unit, 133938389eaaSLijun Ou true, level); 134038389eaaSLijun Ou if (!cur) { 134138389eaaSLijun Ou ret = -ENOMEM; 134238389eaaSLijun Ou goto err_exit; 134338389eaaSLijun Ou } 134438389eaaSLijun Ou hem_ptrs[level] = cur; 134538389eaaSLijun Ou list_add(&cur->list, &temp_list[level]); 134638389eaaSLijun Ou if (hem_list_is_bottom_bt(hopnum, level)) 134738389eaaSLijun Ou list_add(&cur->sibling, &temp_list[0]); 134838389eaaSLijun Ou 134938389eaaSLijun Ou /* link bt to parent bt */ 135038389eaaSLijun Ou if (level > 1) { 135138389eaaSLijun Ou pre = hem_ptrs[level - 1]; 135238389eaaSLijun Ou step = (cur->start - pre->start) / step * BA_BYTE_LEN; 135338389eaaSLijun Ou hem_list_link_bt(hr_dev, pre->addr + step, 135438389eaaSLijun Ou cur->dma_addr); 135538389eaaSLijun Ou } 135638389eaaSLijun Ou } 135738389eaaSLijun Ou 135838389eaaSLijun Ou list_splice(&temp_list[0], btm_bt); 135938389eaaSLijun Ou for (level = 1; level < hopnum; level++) 136038389eaaSLijun Ou list_splice(&temp_list[level], &mid_bt[level]); 136138389eaaSLijun Ou 136238389eaaSLijun Ou return 0; 136338389eaaSLijun Ou 136438389eaaSLijun Ou err_exit: 136538389eaaSLijun Ou for (level = 1; level < hopnum; level++) 136638389eaaSLijun Ou hem_list_free_all(hr_dev, &temp_list[level], true); 136738389eaaSLijun Ou 136838389eaaSLijun Ou return ret; 136938389eaaSLijun Ou } 137038389eaaSLijun Ou 137138389eaaSLijun Ou static int hem_list_alloc_root_bt(struct hns_roce_dev *hr_dev, 137238389eaaSLijun Ou struct hns_roce_hem_list *hem_list, int unit, 137338389eaaSLijun Ou const struct hns_roce_buf_region *regions, 137438389eaaSLijun Ou int region_cnt) 137538389eaaSLijun Ou { 137638389eaaSLijun Ou struct roce_hem_item *hem, *temp_hem, *root_hem; 137738389eaaSLijun Ou struct list_head temp_list[HNS_ROCE_MAX_BT_REGION]; 137838389eaaSLijun Ou const struct hns_roce_buf_region *r; 137938389eaaSLijun Ou struct list_head temp_root; 138038389eaaSLijun Ou struct list_head temp_btm; 138138389eaaSLijun Ou void *cpu_base; 138238389eaaSLijun Ou u64 phy_base; 138338389eaaSLijun Ou int ret = 0; 138438389eaaSLijun Ou int offset; 138538389eaaSLijun Ou int total; 138638389eaaSLijun Ou int step; 138738389eaaSLijun Ou int i; 138838389eaaSLijun Ou 138938389eaaSLijun Ou r = ®ions[0]; 139038389eaaSLijun Ou root_hem = hem_list_search_item(&hem_list->root_bt, r->offset); 139138389eaaSLijun Ou if (root_hem) 139238389eaaSLijun Ou return 0; 139338389eaaSLijun Ou 139438389eaaSLijun Ou INIT_LIST_HEAD(&temp_root); 139538389eaaSLijun Ou total = r->offset; 139638389eaaSLijun Ou /* indicate to last region */ 139738389eaaSLijun Ou r = ®ions[region_cnt - 1]; 139838389eaaSLijun Ou root_hem = hem_list_alloc_item(hr_dev, total, r->offset + r->count - 1, 139938389eaaSLijun Ou unit, true, 0); 140038389eaaSLijun Ou if (!root_hem) 140138389eaaSLijun Ou return -ENOMEM; 140238389eaaSLijun Ou list_add(&root_hem->list, &temp_root); 140338389eaaSLijun Ou 140438389eaaSLijun Ou hem_list->root_ba = root_hem->dma_addr; 140538389eaaSLijun Ou 140638389eaaSLijun Ou INIT_LIST_HEAD(&temp_btm); 140738389eaaSLijun Ou for (i = 0; i < region_cnt; i++) 140838389eaaSLijun Ou INIT_LIST_HEAD(&temp_list[i]); 140938389eaaSLijun Ou 141038389eaaSLijun Ou total = 0; 141138389eaaSLijun Ou for (i = 0; i < region_cnt && total < unit; i++) { 141238389eaaSLijun Ou r = ®ions[i]; 141338389eaaSLijun Ou if (!r->count) 141438389eaaSLijun Ou continue; 141538389eaaSLijun Ou 141638389eaaSLijun Ou /* all regions's mid[x][0] shared the root_bt's trunk */ 141738389eaaSLijun Ou cpu_base = root_hem->addr + total * BA_BYTE_LEN; 141838389eaaSLijun Ou phy_base = root_hem->dma_addr + total * BA_BYTE_LEN; 141938389eaaSLijun Ou 142038389eaaSLijun Ou /* if hopnum is 0 or 1, cut a new fake hem from the root bt 142138389eaaSLijun Ou * which's address share to all regions. 142238389eaaSLijun Ou */ 142338389eaaSLijun Ou if (hem_list_is_bottom_bt(r->hopnum, 0)) { 142438389eaaSLijun Ou hem = hem_list_alloc_item(hr_dev, r->offset, 142538389eaaSLijun Ou r->offset + r->count - 1, 142638389eaaSLijun Ou r->count, false, 0); 142738389eaaSLijun Ou if (!hem) { 142838389eaaSLijun Ou ret = -ENOMEM; 142938389eaaSLijun Ou goto err_exit; 143038389eaaSLijun Ou } 143138389eaaSLijun Ou hem_list_assign_bt(hr_dev, hem, cpu_base, phy_base); 143238389eaaSLijun Ou list_add(&hem->list, &temp_list[i]); 143338389eaaSLijun Ou list_add(&hem->sibling, &temp_btm); 143438389eaaSLijun Ou total += r->count; 143538389eaaSLijun Ou } else { 143638389eaaSLijun Ou step = hem_list_calc_ba_range(r->hopnum, 1, unit); 143738389eaaSLijun Ou if (step < 1) { 143838389eaaSLijun Ou ret = -EINVAL; 143938389eaaSLijun Ou goto err_exit; 144038389eaaSLijun Ou } 144138389eaaSLijun Ou /* if exist mid bt, link L1 to L0 */ 144238389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, 144338389eaaSLijun Ou &hem_list->mid_bt[i][1], list) { 144438389eaaSLijun Ou offset = hem->start / step * BA_BYTE_LEN; 144538389eaaSLijun Ou hem_list_link_bt(hr_dev, cpu_base + offset, 144638389eaaSLijun Ou hem->dma_addr); 144738389eaaSLijun Ou total++; 144838389eaaSLijun Ou } 144938389eaaSLijun Ou } 145038389eaaSLijun Ou } 145138389eaaSLijun Ou 145238389eaaSLijun Ou list_splice(&temp_btm, &hem_list->btm_bt); 145338389eaaSLijun Ou list_splice(&temp_root, &hem_list->root_bt); 145438389eaaSLijun Ou for (i = 0; i < region_cnt; i++) 145538389eaaSLijun Ou list_splice(&temp_list[i], &hem_list->mid_bt[i][0]); 145638389eaaSLijun Ou 145738389eaaSLijun Ou return 0; 145838389eaaSLijun Ou 145938389eaaSLijun Ou err_exit: 146038389eaaSLijun Ou for (i = 0; i < region_cnt; i++) 146138389eaaSLijun Ou hem_list_free_all(hr_dev, &temp_list[i], false); 146238389eaaSLijun Ou 146338389eaaSLijun Ou hem_list_free_all(hr_dev, &temp_root, true); 146438389eaaSLijun Ou 146538389eaaSLijun Ou return ret; 146638389eaaSLijun Ou } 146738389eaaSLijun Ou 146838389eaaSLijun Ou /* construct the base address table and link them by address hop config */ 146938389eaaSLijun Ou int hns_roce_hem_list_request(struct hns_roce_dev *hr_dev, 147038389eaaSLijun Ou struct hns_roce_hem_list *hem_list, 147138389eaaSLijun Ou const struct hns_roce_buf_region *regions, 147238389eaaSLijun Ou int region_cnt) 147338389eaaSLijun Ou { 147438389eaaSLijun Ou const struct hns_roce_buf_region *r; 147538389eaaSLijun Ou int ofs, end; 147638389eaaSLijun Ou int ret = 0; 147738389eaaSLijun Ou int unit; 147838389eaaSLijun Ou int i; 147938389eaaSLijun Ou 148038389eaaSLijun Ou if (region_cnt > HNS_ROCE_MAX_BT_REGION) { 148138389eaaSLijun Ou dev_err(hr_dev->dev, "invalid region region_cnt %d!\n", 148238389eaaSLijun Ou region_cnt); 148338389eaaSLijun Ou return -EINVAL; 148438389eaaSLijun Ou } 148538389eaaSLijun Ou 148638389eaaSLijun Ou unit = (1 << hem_list->bt_pg_shift) / BA_BYTE_LEN; 148738389eaaSLijun Ou for (i = 0; i < region_cnt; i++) { 148838389eaaSLijun Ou r = ®ions[i]; 148938389eaaSLijun Ou if (!r->count) 149038389eaaSLijun Ou continue; 149138389eaaSLijun Ou 149238389eaaSLijun Ou end = r->offset + r->count; 149338389eaaSLijun Ou for (ofs = r->offset; ofs < end; ofs += unit) { 149438389eaaSLijun Ou ret = hem_list_alloc_mid_bt(hr_dev, r, unit, ofs, 149538389eaaSLijun Ou hem_list->mid_bt[i], 149638389eaaSLijun Ou &hem_list->btm_bt); 149738389eaaSLijun Ou if (ret) { 149838389eaaSLijun Ou dev_err(hr_dev->dev, 149938389eaaSLijun Ou "alloc hem trunk fail ret=%d!\n", ret); 150038389eaaSLijun Ou goto err_alloc; 150138389eaaSLijun Ou } 150238389eaaSLijun Ou } 150338389eaaSLijun Ou } 150438389eaaSLijun Ou 150538389eaaSLijun Ou ret = hem_list_alloc_root_bt(hr_dev, hem_list, unit, regions, 150638389eaaSLijun Ou region_cnt); 150738389eaaSLijun Ou if (ret) 150838389eaaSLijun Ou dev_err(hr_dev->dev, "alloc hem root fail ret=%d!\n", ret); 150938389eaaSLijun Ou else 151038389eaaSLijun Ou return 0; 151138389eaaSLijun Ou 151238389eaaSLijun Ou err_alloc: 151338389eaaSLijun Ou hns_roce_hem_list_release(hr_dev, hem_list); 151438389eaaSLijun Ou 151538389eaaSLijun Ou return ret; 151638389eaaSLijun Ou } 151738389eaaSLijun Ou 151838389eaaSLijun Ou void hns_roce_hem_list_release(struct hns_roce_dev *hr_dev, 151938389eaaSLijun Ou struct hns_roce_hem_list *hem_list) 152038389eaaSLijun Ou { 152138389eaaSLijun Ou int i, j; 152238389eaaSLijun Ou 152338389eaaSLijun Ou for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++) 152438389eaaSLijun Ou for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++) 152538389eaaSLijun Ou hem_list_free_all(hr_dev, &hem_list->mid_bt[i][j], 152638389eaaSLijun Ou j != 0); 152738389eaaSLijun Ou 152838389eaaSLijun Ou hem_list_free_all(hr_dev, &hem_list->root_bt, true); 152938389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->btm_bt); 153038389eaaSLijun Ou hem_list->root_ba = 0; 153138389eaaSLijun Ou } 153238389eaaSLijun Ou 153338389eaaSLijun Ou void hns_roce_hem_list_init(struct hns_roce_hem_list *hem_list, 153438389eaaSLijun Ou int bt_page_order) 153538389eaaSLijun Ou { 153638389eaaSLijun Ou int i, j; 153738389eaaSLijun Ou 153838389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->root_bt); 153938389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->btm_bt); 154038389eaaSLijun Ou for (i = 0; i < HNS_ROCE_MAX_BT_REGION; i++) 154138389eaaSLijun Ou for (j = 0; j < HNS_ROCE_MAX_BT_LEVEL; j++) 154238389eaaSLijun Ou INIT_LIST_HEAD(&hem_list->mid_bt[i][j]); 154338389eaaSLijun Ou 154438389eaaSLijun Ou hem_list->bt_pg_shift = bt_page_order; 154538389eaaSLijun Ou } 154638389eaaSLijun Ou 154738389eaaSLijun Ou void *hns_roce_hem_list_find_mtt(struct hns_roce_dev *hr_dev, 154838389eaaSLijun Ou struct hns_roce_hem_list *hem_list, 154938389eaaSLijun Ou int offset, int *mtt_cnt, u64 *phy_addr) 155038389eaaSLijun Ou { 155138389eaaSLijun Ou struct list_head *head = &hem_list->btm_bt; 155238389eaaSLijun Ou struct roce_hem_item *hem, *temp_hem; 155338389eaaSLijun Ou void *cpu_base = NULL; 155438389eaaSLijun Ou u64 phy_base = 0; 155538389eaaSLijun Ou int nr = 0; 155638389eaaSLijun Ou 155738389eaaSLijun Ou list_for_each_entry_safe(hem, temp_hem, head, sibling) { 155838389eaaSLijun Ou if (hem_list_page_is_in_range(hem, offset)) { 155938389eaaSLijun Ou nr = offset - hem->start; 156038389eaaSLijun Ou cpu_base = hem->addr + nr * BA_BYTE_LEN; 156138389eaaSLijun Ou phy_base = hem->dma_addr + nr * BA_BYTE_LEN; 156238389eaaSLijun Ou nr = hem->end + 1 - offset; 156338389eaaSLijun Ou break; 156438389eaaSLijun Ou } 156538389eaaSLijun Ou } 156638389eaaSLijun Ou 156738389eaaSLijun Ou if (mtt_cnt) 156838389eaaSLijun Ou *mtt_cnt = nr; 156938389eaaSLijun Ou 157038389eaaSLijun Ou if (phy_addr) 157138389eaaSLijun Ou *phy_addr = phy_base; 157238389eaaSLijun Ou 157338389eaaSLijun Ou return cpu_base; 157438389eaaSLijun Ou } 1575