xref: /freebsd/sys/dev/irdma/irdma_pble.c (revision 01fbb869)
1cdcd52d4SBartosz Sobczak /*-
2cdcd52d4SBartosz Sobczak  * SPDX-License-Identifier: GPL-2.0 or Linux-OpenIB
3cdcd52d4SBartosz Sobczak  *
401fbb869SBartosz Sobczak  * Copyright (c) 2015 - 2023 Intel Corporation
5cdcd52d4SBartosz Sobczak  *
6cdcd52d4SBartosz Sobczak  * This software is available to you under a choice of one of two
7cdcd52d4SBartosz Sobczak  * licenses.  You may choose to be licensed under the terms of the GNU
8cdcd52d4SBartosz Sobczak  * General Public License (GPL) Version 2, available from the file
9cdcd52d4SBartosz Sobczak  * COPYING in the main directory of this source tree, or the
10cdcd52d4SBartosz Sobczak  * OpenFabrics.org BSD license below:
11cdcd52d4SBartosz Sobczak  *
12cdcd52d4SBartosz Sobczak  *   Redistribution and use in source and binary forms, with or
13cdcd52d4SBartosz Sobczak  *   without modification, are permitted provided that the following
14cdcd52d4SBartosz Sobczak  *   conditions are met:
15cdcd52d4SBartosz Sobczak  *
16cdcd52d4SBartosz Sobczak  *    - Redistributions of source code must retain the above
17cdcd52d4SBartosz Sobczak  *	copyright notice, this list of conditions and the following
18cdcd52d4SBartosz Sobczak  *	disclaimer.
19cdcd52d4SBartosz Sobczak  *
20cdcd52d4SBartosz Sobczak  *    - Redistributions in binary form must reproduce the above
21cdcd52d4SBartosz Sobczak  *	copyright notice, this list of conditions and the following
22cdcd52d4SBartosz Sobczak  *	disclaimer in the documentation and/or other materials
23cdcd52d4SBartosz Sobczak  *	provided with the distribution.
24cdcd52d4SBartosz Sobczak  *
25cdcd52d4SBartosz Sobczak  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26cdcd52d4SBartosz Sobczak  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27cdcd52d4SBartosz Sobczak  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28cdcd52d4SBartosz Sobczak  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29cdcd52d4SBartosz Sobczak  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30cdcd52d4SBartosz Sobczak  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31cdcd52d4SBartosz Sobczak  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32cdcd52d4SBartosz Sobczak  * SOFTWARE.
33cdcd52d4SBartosz Sobczak  */
34cdcd52d4SBartosz Sobczak 
35cdcd52d4SBartosz Sobczak #include "osdep.h"
36cdcd52d4SBartosz Sobczak #include "irdma_hmc.h"
37cdcd52d4SBartosz Sobczak #include "irdma_defs.h"
38cdcd52d4SBartosz Sobczak #include "irdma_type.h"
39cdcd52d4SBartosz Sobczak #include "irdma_protos.h"
40cdcd52d4SBartosz Sobczak #include "irdma_pble.h"
41cdcd52d4SBartosz Sobczak 
42cdcd52d4SBartosz Sobczak static int add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc);
43cdcd52d4SBartosz Sobczak 
44cdcd52d4SBartosz Sobczak /**
45cdcd52d4SBartosz Sobczak  * irdma_destroy_pble_prm - destroy prm during module unload
46cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resources
47cdcd52d4SBartosz Sobczak  */
48cdcd52d4SBartosz Sobczak void
irdma_destroy_pble_prm(struct irdma_hmc_pble_rsrc * pble_rsrc)49cdcd52d4SBartosz Sobczak irdma_destroy_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
50cdcd52d4SBartosz Sobczak {
51cdcd52d4SBartosz Sobczak 	struct irdma_chunk *chunk;
52cdcd52d4SBartosz Sobczak 	struct irdma_pble_prm *pinfo = &pble_rsrc->pinfo;
53cdcd52d4SBartosz Sobczak 
54cdcd52d4SBartosz Sobczak 	while (!list_empty(&pinfo->clist)) {
55cdcd52d4SBartosz Sobczak 		chunk = (struct irdma_chunk *)(&pinfo->clist)->next;
56cdcd52d4SBartosz Sobczak 		list_del(&chunk->list);
57cdcd52d4SBartosz Sobczak 		if (chunk->type == PBLE_SD_PAGED)
58cdcd52d4SBartosz Sobczak 			irdma_pble_free_paged_mem(chunk);
5901fbb869SBartosz Sobczak 		bitmap_free(chunk->bitmapbuf);
60cdcd52d4SBartosz Sobczak 		kfree(chunk->chunkmem.va);
61cdcd52d4SBartosz Sobczak 	}
62cdcd52d4SBartosz Sobczak 	spin_lock_destroy(&pinfo->prm_lock);
63cdcd52d4SBartosz Sobczak 	mutex_destroy(&pble_rsrc->pble_mutex_lock);
64cdcd52d4SBartosz Sobczak }
65cdcd52d4SBartosz Sobczak 
66cdcd52d4SBartosz Sobczak /**
67cdcd52d4SBartosz Sobczak  * irdma_hmc_init_pble - Initialize pble resources during module load
68cdcd52d4SBartosz Sobczak  * @dev: irdma_sc_dev struct
69cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resources
70cdcd52d4SBartosz Sobczak  */
71cdcd52d4SBartosz Sobczak int
irdma_hmc_init_pble(struct irdma_sc_dev * dev,struct irdma_hmc_pble_rsrc * pble_rsrc)72cdcd52d4SBartosz Sobczak irdma_hmc_init_pble(struct irdma_sc_dev *dev,
73cdcd52d4SBartosz Sobczak 		    struct irdma_hmc_pble_rsrc *pble_rsrc)
74cdcd52d4SBartosz Sobczak {
75cdcd52d4SBartosz Sobczak 	struct irdma_hmc_info *hmc_info;
76cdcd52d4SBartosz Sobczak 	u32 fpm_idx = 0;
77cdcd52d4SBartosz Sobczak 	int status = 0;
78cdcd52d4SBartosz Sobczak 
79cdcd52d4SBartosz Sobczak 	hmc_info = dev->hmc_info;
80cdcd52d4SBartosz Sobczak 	pble_rsrc->dev = dev;
81cdcd52d4SBartosz Sobczak 	pble_rsrc->fpm_base_addr = hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].base;
82cdcd52d4SBartosz Sobczak 	/* Start pble' on 4k boundary */
83cdcd52d4SBartosz Sobczak 	if (pble_rsrc->fpm_base_addr & 0xfff)
84cdcd52d4SBartosz Sobczak 		fpm_idx = (4096 - (pble_rsrc->fpm_base_addr & 0xfff)) >> 3;
85cdcd52d4SBartosz Sobczak 	pble_rsrc->unallocated_pble =
86cdcd52d4SBartosz Sobczak 	    hmc_info->hmc_obj[IRDMA_HMC_IW_PBLE].cnt - fpm_idx;
87cdcd52d4SBartosz Sobczak 	pble_rsrc->next_fpm_addr = pble_rsrc->fpm_base_addr + (fpm_idx << 3);
88cdcd52d4SBartosz Sobczak 	pble_rsrc->pinfo.pble_shift = PBLE_SHIFT;
89cdcd52d4SBartosz Sobczak 
90cdcd52d4SBartosz Sobczak 	mutex_init(&pble_rsrc->pble_mutex_lock);
91cdcd52d4SBartosz Sobczak 
92cdcd52d4SBartosz Sobczak 	spin_lock_init(&pble_rsrc->pinfo.prm_lock);
93cdcd52d4SBartosz Sobczak 	INIT_LIST_HEAD(&pble_rsrc->pinfo.clist);
94cdcd52d4SBartosz Sobczak 	if (add_pble_prm(pble_rsrc)) {
95cdcd52d4SBartosz Sobczak 		irdma_destroy_pble_prm(pble_rsrc);
96cdcd52d4SBartosz Sobczak 		status = -ENOMEM;
97cdcd52d4SBartosz Sobczak 	}
98cdcd52d4SBartosz Sobczak 
99cdcd52d4SBartosz Sobczak 	return status;
100cdcd52d4SBartosz Sobczak }
101cdcd52d4SBartosz Sobczak 
102cdcd52d4SBartosz Sobczak /**
103cdcd52d4SBartosz Sobczak  * get_sd_pd_idx -  Returns sd index, pd index and rel_pd_idx from fpm address
104cdcd52d4SBartosz Sobczak  * @pble_rsrc: structure containing fpm address
105cdcd52d4SBartosz Sobczak  * @idx: where to return indexes
106cdcd52d4SBartosz Sobczak  */
107cdcd52d4SBartosz Sobczak static void
get_sd_pd_idx(struct irdma_hmc_pble_rsrc * pble_rsrc,struct sd_pd_idx * idx)108cdcd52d4SBartosz Sobczak get_sd_pd_idx(struct irdma_hmc_pble_rsrc *pble_rsrc,
109cdcd52d4SBartosz Sobczak 	      struct sd_pd_idx *idx)
110cdcd52d4SBartosz Sobczak {
111cdcd52d4SBartosz Sobczak 	idx->sd_idx = (u32)pble_rsrc->next_fpm_addr / IRDMA_HMC_DIRECT_BP_SIZE;
112cdcd52d4SBartosz Sobczak 	idx->pd_idx = (u32)(pble_rsrc->next_fpm_addr / IRDMA_HMC_PAGED_BP_SIZE);
113cdcd52d4SBartosz Sobczak 	idx->rel_pd_idx = (idx->pd_idx % IRDMA_HMC_PD_CNT_IN_SD);
114cdcd52d4SBartosz Sobczak }
115cdcd52d4SBartosz Sobczak 
116cdcd52d4SBartosz Sobczak /**
117cdcd52d4SBartosz Sobczak  * add_sd_direct - add sd direct for pble
118cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource ptr
119cdcd52d4SBartosz Sobczak  * @info: page info for sd
120cdcd52d4SBartosz Sobczak  */
121cdcd52d4SBartosz Sobczak static int
add_sd_direct(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_add_page_info * info)122cdcd52d4SBartosz Sobczak add_sd_direct(struct irdma_hmc_pble_rsrc *pble_rsrc,
123cdcd52d4SBartosz Sobczak 	      struct irdma_add_page_info *info)
124cdcd52d4SBartosz Sobczak {
125cdcd52d4SBartosz Sobczak 	struct irdma_sc_dev *dev = pble_rsrc->dev;
126cdcd52d4SBartosz Sobczak 	int ret_code = 0;
127cdcd52d4SBartosz Sobczak 	struct sd_pd_idx *idx = &info->idx;
128cdcd52d4SBartosz Sobczak 	struct irdma_chunk *chunk = info->chunk;
129cdcd52d4SBartosz Sobczak 	struct irdma_hmc_info *hmc_info = info->hmc_info;
130cdcd52d4SBartosz Sobczak 	struct irdma_hmc_sd_entry *sd_entry = info->sd_entry;
131cdcd52d4SBartosz Sobczak 	u32 offset = 0;
132cdcd52d4SBartosz Sobczak 
133cdcd52d4SBartosz Sobczak 	if (!sd_entry->valid) {
134cdcd52d4SBartosz Sobczak 		ret_code = irdma_add_sd_table_entry(dev->hw, hmc_info,
135cdcd52d4SBartosz Sobczak 						    info->idx.sd_idx,
136cdcd52d4SBartosz Sobczak 						    IRDMA_SD_TYPE_DIRECT,
137cdcd52d4SBartosz Sobczak 						    IRDMA_HMC_DIRECT_BP_SIZE);
138cdcd52d4SBartosz Sobczak 		if (ret_code)
139cdcd52d4SBartosz Sobczak 			return ret_code;
140cdcd52d4SBartosz Sobczak 
141cdcd52d4SBartosz Sobczak 		chunk->type = PBLE_SD_CONTIGOUS;
142cdcd52d4SBartosz Sobczak 	}
143cdcd52d4SBartosz Sobczak 
144cdcd52d4SBartosz Sobczak 	offset = idx->rel_pd_idx << HMC_PAGED_BP_SHIFT;
145cdcd52d4SBartosz Sobczak 	chunk->size = info->pages << HMC_PAGED_BP_SHIFT;
146cdcd52d4SBartosz Sobczak 	chunk->vaddr = (u8 *)sd_entry->u.bp.addr.va + offset;
147cdcd52d4SBartosz Sobczak 	chunk->fpm_addr = pble_rsrc->next_fpm_addr;
148cdcd52d4SBartosz Sobczak 	irdma_debug(dev, IRDMA_DEBUG_PBLE,
149cdcd52d4SBartosz Sobczak 		    "chunk_size[%ld] = 0x%lx vaddr=0x%p fpm_addr = %lx\n",
150cdcd52d4SBartosz Sobczak 		    chunk->size, chunk->size, chunk->vaddr, chunk->fpm_addr);
151cdcd52d4SBartosz Sobczak 
152cdcd52d4SBartosz Sobczak 	return 0;
153cdcd52d4SBartosz Sobczak }
154cdcd52d4SBartosz Sobczak 
155cdcd52d4SBartosz Sobczak /**
156cdcd52d4SBartosz Sobczak  * fpm_to_idx - given fpm address, get pble index
157cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource management
158cdcd52d4SBartosz Sobczak  * @addr: fpm address for index
159cdcd52d4SBartosz Sobczak  */
fpm_to_idx(struct irdma_hmc_pble_rsrc * pble_rsrc,u64 addr)160cdcd52d4SBartosz Sobczak static u32 fpm_to_idx(struct irdma_hmc_pble_rsrc *pble_rsrc, u64 addr){
161cdcd52d4SBartosz Sobczak 	u64 idx;
162cdcd52d4SBartosz Sobczak 
163cdcd52d4SBartosz Sobczak 	idx = (addr - (pble_rsrc->fpm_base_addr)) >> 3;
164cdcd52d4SBartosz Sobczak 
165cdcd52d4SBartosz Sobczak 	return (u32)idx;
166cdcd52d4SBartosz Sobczak }
167cdcd52d4SBartosz Sobczak 
168cdcd52d4SBartosz Sobczak /**
169cdcd52d4SBartosz Sobczak  * add_bp_pages - add backing pages for sd
170cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource management
171cdcd52d4SBartosz Sobczak  * @info: page info for sd
172cdcd52d4SBartosz Sobczak  */
173cdcd52d4SBartosz Sobczak static int
add_bp_pages(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_add_page_info * info)174cdcd52d4SBartosz Sobczak add_bp_pages(struct irdma_hmc_pble_rsrc *pble_rsrc,
175cdcd52d4SBartosz Sobczak 	     struct irdma_add_page_info *info)
176cdcd52d4SBartosz Sobczak {
177cdcd52d4SBartosz Sobczak 	struct irdma_sc_dev *dev = pble_rsrc->dev;
178cdcd52d4SBartosz Sobczak 	u8 *addr;
179cdcd52d4SBartosz Sobczak 	struct irdma_dma_mem mem;
180cdcd52d4SBartosz Sobczak 	struct irdma_hmc_pd_entry *pd_entry;
181cdcd52d4SBartosz Sobczak 	struct irdma_hmc_sd_entry *sd_entry = info->sd_entry;
182cdcd52d4SBartosz Sobczak 	struct irdma_hmc_info *hmc_info = info->hmc_info;
183cdcd52d4SBartosz Sobczak 	struct irdma_chunk *chunk = info->chunk;
184cdcd52d4SBartosz Sobczak 	int status = 0;
185cdcd52d4SBartosz Sobczak 	u32 rel_pd_idx = info->idx.rel_pd_idx;
186cdcd52d4SBartosz Sobczak 	u32 pd_idx = info->idx.pd_idx;
187cdcd52d4SBartosz Sobczak 	u32 i;
188cdcd52d4SBartosz Sobczak 
189cdcd52d4SBartosz Sobczak 	if (irdma_pble_get_paged_mem(chunk, info->pages))
190cdcd52d4SBartosz Sobczak 		return -ENOMEM;
191cdcd52d4SBartosz Sobczak 
192cdcd52d4SBartosz Sobczak 	status = irdma_add_sd_table_entry(dev->hw, hmc_info, info->idx.sd_idx,
193cdcd52d4SBartosz Sobczak 					  IRDMA_SD_TYPE_PAGED,
194cdcd52d4SBartosz Sobczak 					  IRDMA_HMC_DIRECT_BP_SIZE);
195cdcd52d4SBartosz Sobczak 	if (status)
196cdcd52d4SBartosz Sobczak 		goto error;
197cdcd52d4SBartosz Sobczak 
198cdcd52d4SBartosz Sobczak 	addr = chunk->vaddr;
199cdcd52d4SBartosz Sobczak 	for (i = 0; i < info->pages; i++) {
200cdcd52d4SBartosz Sobczak 		mem.pa = (u64)chunk->dmainfo.dmaaddrs[i];
201cdcd52d4SBartosz Sobczak 		mem.size = 4096;
202cdcd52d4SBartosz Sobczak 		mem.va = addr;
203cdcd52d4SBartosz Sobczak 		pd_entry = &sd_entry->u.pd_table.pd_entry[rel_pd_idx++];
204cdcd52d4SBartosz Sobczak 		if (!pd_entry->valid) {
205cdcd52d4SBartosz Sobczak 			status = irdma_add_pd_table_entry(dev, hmc_info,
206cdcd52d4SBartosz Sobczak 							  pd_idx++, &mem);
207cdcd52d4SBartosz Sobczak 			if (status)
208cdcd52d4SBartosz Sobczak 				goto error;
209cdcd52d4SBartosz Sobczak 
210cdcd52d4SBartosz Sobczak 			addr += 4096;
211cdcd52d4SBartosz Sobczak 		}
212cdcd52d4SBartosz Sobczak 	}
213cdcd52d4SBartosz Sobczak 
214cdcd52d4SBartosz Sobczak 	chunk->fpm_addr = pble_rsrc->next_fpm_addr;
215cdcd52d4SBartosz Sobczak 	return 0;
216cdcd52d4SBartosz Sobczak 
217cdcd52d4SBartosz Sobczak error:
218cdcd52d4SBartosz Sobczak 	irdma_pble_free_paged_mem(chunk);
219cdcd52d4SBartosz Sobczak 
220cdcd52d4SBartosz Sobczak 	return status;
221cdcd52d4SBartosz Sobczak }
222cdcd52d4SBartosz Sobczak 
223cdcd52d4SBartosz Sobczak /**
224cdcd52d4SBartosz Sobczak  * irdma_get_type - add a sd entry type for sd
225cdcd52d4SBartosz Sobczak  * @dev: irdma_sc_dev struct
226cdcd52d4SBartosz Sobczak  * @idx: index of sd
227cdcd52d4SBartosz Sobczak  * @pages: pages in the sd
228cdcd52d4SBartosz Sobczak  */
229cdcd52d4SBartosz Sobczak static enum irdma_sd_entry_type
irdma_get_type(struct irdma_sc_dev * dev,struct sd_pd_idx * idx,u32 pages)230cdcd52d4SBartosz Sobczak irdma_get_type(struct irdma_sc_dev *dev,
231cdcd52d4SBartosz Sobczak 	       struct sd_pd_idx *idx, u32 pages)
232cdcd52d4SBartosz Sobczak {
233cdcd52d4SBartosz Sobczak 	enum irdma_sd_entry_type sd_entry_type;
234cdcd52d4SBartosz Sobczak 
235cdcd52d4SBartosz Sobczak 	sd_entry_type = !idx->rel_pd_idx && pages == IRDMA_HMC_PD_CNT_IN_SD ?
236cdcd52d4SBartosz Sobczak 	    IRDMA_SD_TYPE_DIRECT : IRDMA_SD_TYPE_PAGED;
237cdcd52d4SBartosz Sobczak 	return sd_entry_type;
238cdcd52d4SBartosz Sobczak }
239cdcd52d4SBartosz Sobczak 
240cdcd52d4SBartosz Sobczak /**
241cdcd52d4SBartosz Sobczak  * add_pble_prm - add a sd entry for pble resoure
242cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource management
243cdcd52d4SBartosz Sobczak  */
244cdcd52d4SBartosz Sobczak static int
add_pble_prm(struct irdma_hmc_pble_rsrc * pble_rsrc)245cdcd52d4SBartosz Sobczak add_pble_prm(struct irdma_hmc_pble_rsrc *pble_rsrc)
246cdcd52d4SBartosz Sobczak {
247cdcd52d4SBartosz Sobczak 	struct irdma_sc_dev *dev = pble_rsrc->dev;
248cdcd52d4SBartosz Sobczak 	struct irdma_hmc_sd_entry *sd_entry;
249cdcd52d4SBartosz Sobczak 	struct irdma_hmc_info *hmc_info;
250cdcd52d4SBartosz Sobczak 	struct irdma_chunk *chunk;
251cdcd52d4SBartosz Sobczak 	struct irdma_add_page_info info;
252cdcd52d4SBartosz Sobczak 	struct sd_pd_idx *idx = &info.idx;
253cdcd52d4SBartosz Sobczak 	int ret_code = 0;
254cdcd52d4SBartosz Sobczak 	enum irdma_sd_entry_type sd_entry_type;
255cdcd52d4SBartosz Sobczak 	u64 sd_reg_val = 0;
256cdcd52d4SBartosz Sobczak 	struct irdma_virt_mem chunkmem;
257cdcd52d4SBartosz Sobczak 	u32 pages;
258cdcd52d4SBartosz Sobczak 
259cdcd52d4SBartosz Sobczak 	if (pble_rsrc->unallocated_pble < PBLE_PER_PAGE)
260cdcd52d4SBartosz Sobczak 		return -ENOMEM;
261cdcd52d4SBartosz Sobczak 
262cdcd52d4SBartosz Sobczak 	if (pble_rsrc->next_fpm_addr & 0xfff)
263cdcd52d4SBartosz Sobczak 		return -EINVAL;
264cdcd52d4SBartosz Sobczak 
265cdcd52d4SBartosz Sobczak 	chunkmem.size = sizeof(*chunk);
266777e472cSBartosz Sobczak 	chunkmem.va = kzalloc(chunkmem.size, GFP_KERNEL);
267cdcd52d4SBartosz Sobczak 	if (!chunkmem.va)
268cdcd52d4SBartosz Sobczak 		return -ENOMEM;
269cdcd52d4SBartosz Sobczak 
270cdcd52d4SBartosz Sobczak 	chunk = chunkmem.va;
271cdcd52d4SBartosz Sobczak 	chunk->chunkmem = chunkmem;
272cdcd52d4SBartosz Sobczak 	hmc_info = dev->hmc_info;
273cdcd52d4SBartosz Sobczak 	chunk->dev = dev;
274cdcd52d4SBartosz Sobczak 	chunk->fpm_addr = pble_rsrc->next_fpm_addr;
275cdcd52d4SBartosz Sobczak 	get_sd_pd_idx(pble_rsrc, idx);
276cdcd52d4SBartosz Sobczak 	sd_entry = &hmc_info->sd_table.sd_entry[idx->sd_idx];
277cdcd52d4SBartosz Sobczak 	pages = (idx->rel_pd_idx) ? (IRDMA_HMC_PD_CNT_IN_SD - idx->rel_pd_idx) :
278cdcd52d4SBartosz Sobczak 	    IRDMA_HMC_PD_CNT_IN_SD;
279cdcd52d4SBartosz Sobczak 	pages = min(pages, pble_rsrc->unallocated_pble >> PBLE_512_SHIFT);
280cdcd52d4SBartosz Sobczak 	info.chunk = chunk;
281cdcd52d4SBartosz Sobczak 	info.hmc_info = hmc_info;
282cdcd52d4SBartosz Sobczak 	info.pages = pages;
283cdcd52d4SBartosz Sobczak 	info.sd_entry = sd_entry;
284cdcd52d4SBartosz Sobczak 	if (!sd_entry->valid)
285cdcd52d4SBartosz Sobczak 		sd_entry_type = irdma_get_type(dev, idx, pages);
286cdcd52d4SBartosz Sobczak 	else
287cdcd52d4SBartosz Sobczak 		sd_entry_type = sd_entry->entry_type;
288cdcd52d4SBartosz Sobczak 
289cdcd52d4SBartosz Sobczak 	irdma_debug(dev, IRDMA_DEBUG_PBLE,
290cdcd52d4SBartosz Sobczak 		    "pages = %d, unallocated_pble[%d] current_fpm_addr = %lx\n",
29101fbb869SBartosz Sobczak 		    pages, pble_rsrc->unallocated_pble,
29201fbb869SBartosz Sobczak 		    pble_rsrc->next_fpm_addr);
293cdcd52d4SBartosz Sobczak 	irdma_debug(dev, IRDMA_DEBUG_PBLE, "sd_entry_type = %d\n",
294cdcd52d4SBartosz Sobczak 		    sd_entry_type);
295cdcd52d4SBartosz Sobczak 	if (sd_entry_type == IRDMA_SD_TYPE_DIRECT)
296cdcd52d4SBartosz Sobczak 		ret_code = add_sd_direct(pble_rsrc, &info);
297cdcd52d4SBartosz Sobczak 
298cdcd52d4SBartosz Sobczak 	if (ret_code)
299cdcd52d4SBartosz Sobczak 		sd_entry_type = IRDMA_SD_TYPE_PAGED;
300cdcd52d4SBartosz Sobczak 	else
301cdcd52d4SBartosz Sobczak 		pble_rsrc->stats_direct_sds++;
302cdcd52d4SBartosz Sobczak 
303cdcd52d4SBartosz Sobczak 	if (sd_entry_type == IRDMA_SD_TYPE_PAGED) {
304cdcd52d4SBartosz Sobczak 		ret_code = add_bp_pages(pble_rsrc, &info);
305cdcd52d4SBartosz Sobczak 		if (ret_code)
30601fbb869SBartosz Sobczak 			goto err_bp_pages;
307cdcd52d4SBartosz Sobczak 		else
308cdcd52d4SBartosz Sobczak 			pble_rsrc->stats_paged_sds++;
309cdcd52d4SBartosz Sobczak 	}
310cdcd52d4SBartosz Sobczak 
311cdcd52d4SBartosz Sobczak 	ret_code = irdma_prm_add_pble_mem(&pble_rsrc->pinfo, chunk);
312cdcd52d4SBartosz Sobczak 	if (ret_code)
31301fbb869SBartosz Sobczak 		goto err_bp_pages;
314cdcd52d4SBartosz Sobczak 
315cdcd52d4SBartosz Sobczak 	pble_rsrc->next_fpm_addr += chunk->size;
316cdcd52d4SBartosz Sobczak 	irdma_debug(dev, IRDMA_DEBUG_PBLE,
317cdcd52d4SBartosz Sobczak 		    "next_fpm_addr = %lx chunk_size[%lu] = 0x%lx\n",
318cdcd52d4SBartosz Sobczak 		    pble_rsrc->next_fpm_addr, chunk->size, chunk->size);
319cdcd52d4SBartosz Sobczak 	pble_rsrc->unallocated_pble -= (u32)(chunk->size >> 3);
320cdcd52d4SBartosz Sobczak 	sd_reg_val = (sd_entry_type == IRDMA_SD_TYPE_PAGED) ?
321cdcd52d4SBartosz Sobczak 	    sd_entry->u.pd_table.pd_page_addr.pa :
322cdcd52d4SBartosz Sobczak 	    sd_entry->u.bp.addr.pa;
323cdcd52d4SBartosz Sobczak 	if (!sd_entry->valid) {
324cdcd52d4SBartosz Sobczak 		ret_code = irdma_hmc_sd_one(dev, hmc_info->hmc_fn_id, sd_reg_val,
325cdcd52d4SBartosz Sobczak 					    idx->sd_idx, sd_entry->entry_type, true);
326cdcd52d4SBartosz Sobczak 		if (ret_code)
327cdcd52d4SBartosz Sobczak 			goto error;
328cdcd52d4SBartosz Sobczak 	}
329cdcd52d4SBartosz Sobczak 
330cdcd52d4SBartosz Sobczak 	sd_entry->valid = true;
331cdcd52d4SBartosz Sobczak 	list_add(&chunk->list, &pble_rsrc->pinfo.clist);
332cdcd52d4SBartosz Sobczak 	return 0;
333cdcd52d4SBartosz Sobczak 
334cdcd52d4SBartosz Sobczak error:
33501fbb869SBartosz Sobczak 	bitmap_free(chunk->bitmapbuf);
33601fbb869SBartosz Sobczak err_bp_pages:
337cdcd52d4SBartosz Sobczak 	kfree(chunk->chunkmem.va);
338cdcd52d4SBartosz Sobczak 
339cdcd52d4SBartosz Sobczak 	return ret_code;
340cdcd52d4SBartosz Sobczak }
341cdcd52d4SBartosz Sobczak 
342cdcd52d4SBartosz Sobczak /**
343cdcd52d4SBartosz Sobczak  * free_lvl2 - fee level 2 pble
344cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource management
345cdcd52d4SBartosz Sobczak  * @palloc: level 2 pble allocation
346cdcd52d4SBartosz Sobczak  */
347cdcd52d4SBartosz Sobczak static void
free_lvl2(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_pble_alloc * palloc)348cdcd52d4SBartosz Sobczak free_lvl2(struct irdma_hmc_pble_rsrc *pble_rsrc,
349cdcd52d4SBartosz Sobczak 	  struct irdma_pble_alloc *palloc)
350cdcd52d4SBartosz Sobczak {
351cdcd52d4SBartosz Sobczak 	u32 i;
352cdcd52d4SBartosz Sobczak 	struct irdma_pble_level2 *lvl2 = &palloc->level2;
353cdcd52d4SBartosz Sobczak 	struct irdma_pble_info *root = &lvl2->root;
354cdcd52d4SBartosz Sobczak 	struct irdma_pble_info *leaf = lvl2->leaf;
355cdcd52d4SBartosz Sobczak 
356cdcd52d4SBartosz Sobczak 	for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
357cdcd52d4SBartosz Sobczak 		if (leaf->addr)
358cdcd52d4SBartosz Sobczak 			irdma_prm_return_pbles(&pble_rsrc->pinfo,
359cdcd52d4SBartosz Sobczak 					       &leaf->chunkinfo);
360cdcd52d4SBartosz Sobczak 		else
361cdcd52d4SBartosz Sobczak 			break;
362cdcd52d4SBartosz Sobczak 	}
363cdcd52d4SBartosz Sobczak 
364cdcd52d4SBartosz Sobczak 	if (root->addr)
365cdcd52d4SBartosz Sobczak 		irdma_prm_return_pbles(&pble_rsrc->pinfo, &root->chunkinfo);
366cdcd52d4SBartosz Sobczak 
367cdcd52d4SBartosz Sobczak 	kfree(lvl2->leafmem.va);
368cdcd52d4SBartosz Sobczak 	lvl2->leaf = NULL;
369cdcd52d4SBartosz Sobczak }
370cdcd52d4SBartosz Sobczak 
371cdcd52d4SBartosz Sobczak /**
372cdcd52d4SBartosz Sobczak  * get_lvl2_pble - get level 2 pble resource
373cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource management
374cdcd52d4SBartosz Sobczak  * @palloc: level 2 pble allocation
375cdcd52d4SBartosz Sobczak  */
376cdcd52d4SBartosz Sobczak static int
get_lvl2_pble(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_pble_alloc * palloc)377cdcd52d4SBartosz Sobczak get_lvl2_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
378cdcd52d4SBartosz Sobczak 	      struct irdma_pble_alloc *palloc)
379cdcd52d4SBartosz Sobczak {
380cdcd52d4SBartosz Sobczak 	u32 lf4k, lflast, total, i;
381cdcd52d4SBartosz Sobczak 	u32 pblcnt = PBLE_PER_PAGE;
382cdcd52d4SBartosz Sobczak 	u64 *addr;
383cdcd52d4SBartosz Sobczak 	struct irdma_pble_level2 *lvl2 = &palloc->level2;
384cdcd52d4SBartosz Sobczak 	struct irdma_pble_info *root = &lvl2->root;
385cdcd52d4SBartosz Sobczak 	struct irdma_pble_info *leaf;
386cdcd52d4SBartosz Sobczak 	int ret_code;
387cdcd52d4SBartosz Sobczak 	u64 fpm_addr;
388cdcd52d4SBartosz Sobczak 
389cdcd52d4SBartosz Sobczak 	/* number of full 512 (4K) leafs) */
390cdcd52d4SBartosz Sobczak 	lf4k = palloc->total_cnt >> 9;
391cdcd52d4SBartosz Sobczak 	lflast = palloc->total_cnt % PBLE_PER_PAGE;
392cdcd52d4SBartosz Sobczak 	total = (lflast == 0) ? lf4k : lf4k + 1;
393cdcd52d4SBartosz Sobczak 	lvl2->leaf_cnt = total;
394cdcd52d4SBartosz Sobczak 
395cdcd52d4SBartosz Sobczak 	lvl2->leafmem.size = (sizeof(*leaf) * total);
396777e472cSBartosz Sobczak 	lvl2->leafmem.va = kzalloc(lvl2->leafmem.size, GFP_KERNEL);
397cdcd52d4SBartosz Sobczak 	if (!lvl2->leafmem.va)
398cdcd52d4SBartosz Sobczak 		return -ENOMEM;
399cdcd52d4SBartosz Sobczak 
400cdcd52d4SBartosz Sobczak 	lvl2->leaf = lvl2->leafmem.va;
401cdcd52d4SBartosz Sobczak 	leaf = lvl2->leaf;
402cdcd52d4SBartosz Sobczak 	ret_code = irdma_prm_get_pbles(&pble_rsrc->pinfo, &root->chunkinfo,
403cdcd52d4SBartosz Sobczak 				       total << 3, &root->addr, &fpm_addr);
404cdcd52d4SBartosz Sobczak 	if (ret_code) {
405cdcd52d4SBartosz Sobczak 		kfree(lvl2->leafmem.va);
406cdcd52d4SBartosz Sobczak 		lvl2->leaf = NULL;
407cdcd52d4SBartosz Sobczak 		return -ENOMEM;
408cdcd52d4SBartosz Sobczak 	}
409cdcd52d4SBartosz Sobczak 
410cdcd52d4SBartosz Sobczak 	root->idx = fpm_to_idx(pble_rsrc, fpm_addr);
411cdcd52d4SBartosz Sobczak 	root->cnt = total;
412cdcd52d4SBartosz Sobczak 	addr = root->addr;
413cdcd52d4SBartosz Sobczak 	for (i = 0; i < total; i++, leaf++) {
414cdcd52d4SBartosz Sobczak 		pblcnt = (lflast && ((i + 1) == total)) ?
415cdcd52d4SBartosz Sobczak 		    lflast : PBLE_PER_PAGE;
416cdcd52d4SBartosz Sobczak 		ret_code = irdma_prm_get_pbles(&pble_rsrc->pinfo,
417cdcd52d4SBartosz Sobczak 					       &leaf->chunkinfo, pblcnt << 3,
418cdcd52d4SBartosz Sobczak 					       &leaf->addr, &fpm_addr);
419cdcd52d4SBartosz Sobczak 		if (ret_code)
420cdcd52d4SBartosz Sobczak 			goto error;
421cdcd52d4SBartosz Sobczak 
422cdcd52d4SBartosz Sobczak 		leaf->idx = fpm_to_idx(pble_rsrc, fpm_addr);
423cdcd52d4SBartosz Sobczak 
424cdcd52d4SBartosz Sobczak 		leaf->cnt = pblcnt;
425cdcd52d4SBartosz Sobczak 		*addr = (u64)leaf->idx;
426cdcd52d4SBartosz Sobczak 		addr++;
427cdcd52d4SBartosz Sobczak 	}
428cdcd52d4SBartosz Sobczak 
429cdcd52d4SBartosz Sobczak 	palloc->level = PBLE_LEVEL_2;
430cdcd52d4SBartosz Sobczak 	pble_rsrc->stats_lvl2++;
431cdcd52d4SBartosz Sobczak 	return 0;
432cdcd52d4SBartosz Sobczak 
433cdcd52d4SBartosz Sobczak error:
434cdcd52d4SBartosz Sobczak 	free_lvl2(pble_rsrc, palloc);
435cdcd52d4SBartosz Sobczak 
436cdcd52d4SBartosz Sobczak 	return -ENOMEM;
437cdcd52d4SBartosz Sobczak }
438cdcd52d4SBartosz Sobczak 
439cdcd52d4SBartosz Sobczak /**
440cdcd52d4SBartosz Sobczak  * get_lvl1_pble - get level 1 pble resource
441cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resource management
442cdcd52d4SBartosz Sobczak  * @palloc: level 1 pble allocation
443cdcd52d4SBartosz Sobczak  */
444cdcd52d4SBartosz Sobczak static int
get_lvl1_pble(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_pble_alloc * palloc)445cdcd52d4SBartosz Sobczak get_lvl1_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
446cdcd52d4SBartosz Sobczak 	      struct irdma_pble_alloc *palloc)
447cdcd52d4SBartosz Sobczak {
448cdcd52d4SBartosz Sobczak 	int ret_code;
449cdcd52d4SBartosz Sobczak 	u64 fpm_addr;
450cdcd52d4SBartosz Sobczak 	struct irdma_pble_info *lvl1 = &palloc->level1;
451cdcd52d4SBartosz Sobczak 
452cdcd52d4SBartosz Sobczak 	ret_code = irdma_prm_get_pbles(&pble_rsrc->pinfo, &lvl1->chunkinfo,
453cdcd52d4SBartosz Sobczak 				       palloc->total_cnt << 3, &lvl1->addr,
454cdcd52d4SBartosz Sobczak 				       &fpm_addr);
455cdcd52d4SBartosz Sobczak 	if (ret_code)
456cdcd52d4SBartosz Sobczak 		return -ENOMEM;
457cdcd52d4SBartosz Sobczak 
458cdcd52d4SBartosz Sobczak 	palloc->level = PBLE_LEVEL_1;
459cdcd52d4SBartosz Sobczak 	lvl1->idx = fpm_to_idx(pble_rsrc, fpm_addr);
460cdcd52d4SBartosz Sobczak 	lvl1->cnt = palloc->total_cnt;
461cdcd52d4SBartosz Sobczak 	pble_rsrc->stats_lvl1++;
462cdcd52d4SBartosz Sobczak 
463cdcd52d4SBartosz Sobczak 	return 0;
464cdcd52d4SBartosz Sobczak }
465cdcd52d4SBartosz Sobczak 
466cdcd52d4SBartosz Sobczak /**
467cdcd52d4SBartosz Sobczak  * get_lvl1_lvl2_pble - calls get_lvl1 and get_lvl2 pble routine
468cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resources
469cdcd52d4SBartosz Sobczak  * @palloc: contains all inforamtion regarding pble (idx + pble addr)
47035105900SBartosz Sobczak  * @lvl: Bitmask for requested pble level
471cdcd52d4SBartosz Sobczak  */
472cdcd52d4SBartosz Sobczak static int
get_lvl1_lvl2_pble(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_pble_alloc * palloc,u8 lvl)473cdcd52d4SBartosz Sobczak get_lvl1_lvl2_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
47435105900SBartosz Sobczak 		   struct irdma_pble_alloc *palloc, u8 lvl)
475cdcd52d4SBartosz Sobczak {
476cdcd52d4SBartosz Sobczak 	int status = 0;
477cdcd52d4SBartosz Sobczak 
478cdcd52d4SBartosz Sobczak 	status = get_lvl1_pble(pble_rsrc, palloc);
47935105900SBartosz Sobczak 	if (!status || lvl == PBLE_LEVEL_1 || palloc->total_cnt <= PBLE_PER_PAGE)
480cdcd52d4SBartosz Sobczak 		return status;
481cdcd52d4SBartosz Sobczak 
482cdcd52d4SBartosz Sobczak 	status = get_lvl2_pble(pble_rsrc, palloc);
483cdcd52d4SBartosz Sobczak 
484cdcd52d4SBartosz Sobczak 	return status;
485cdcd52d4SBartosz Sobczak }
486cdcd52d4SBartosz Sobczak 
487cdcd52d4SBartosz Sobczak /**
488cdcd52d4SBartosz Sobczak  * irdma_get_pble - allocate pbles from the prm
489cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resources
490cdcd52d4SBartosz Sobczak  * @palloc: contains all inforamtion regarding pble (idx + pble addr)
491cdcd52d4SBartosz Sobczak  * @pble_cnt: #of pbles requested
49235105900SBartosz Sobczak  * @lvl: requested pble level mask
493cdcd52d4SBartosz Sobczak  */
494cdcd52d4SBartosz Sobczak int
irdma_get_pble(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_pble_alloc * palloc,u32 pble_cnt,u8 lvl)495cdcd52d4SBartosz Sobczak irdma_get_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
496cdcd52d4SBartosz Sobczak 	       struct irdma_pble_alloc *palloc, u32 pble_cnt,
49735105900SBartosz Sobczak 	       u8 lvl)
498cdcd52d4SBartosz Sobczak {
499cdcd52d4SBartosz Sobczak 	int status = 0;
500cdcd52d4SBartosz Sobczak 	int max_sds = 0;
501cdcd52d4SBartosz Sobczak 	int i;
502cdcd52d4SBartosz Sobczak 
503cdcd52d4SBartosz Sobczak 	palloc->total_cnt = pble_cnt;
504cdcd52d4SBartosz Sobczak 	palloc->level = PBLE_LEVEL_0;
505cdcd52d4SBartosz Sobczak 
506cdcd52d4SBartosz Sobczak 	mutex_lock(&pble_rsrc->pble_mutex_lock);
507cdcd52d4SBartosz Sobczak 
508cdcd52d4SBartosz Sobczak 	/*
509cdcd52d4SBartosz Sobczak 	 * check first to see if we can get pble's without acquiring additional sd's
510cdcd52d4SBartosz Sobczak 	 */
51135105900SBartosz Sobczak 	status = get_lvl1_lvl2_pble(pble_rsrc, palloc, lvl);
512cdcd52d4SBartosz Sobczak 	if (!status)
513cdcd52d4SBartosz Sobczak 		goto exit;
514cdcd52d4SBartosz Sobczak 
515cdcd52d4SBartosz Sobczak 	max_sds = (palloc->total_cnt >> 18) + 1;
516cdcd52d4SBartosz Sobczak 	for (i = 0; i < max_sds; i++) {
517cdcd52d4SBartosz Sobczak 		status = add_pble_prm(pble_rsrc);
518cdcd52d4SBartosz Sobczak 		if (status)
519cdcd52d4SBartosz Sobczak 			break;
520cdcd52d4SBartosz Sobczak 
52135105900SBartosz Sobczak 		status = get_lvl1_lvl2_pble(pble_rsrc, palloc, lvl);
522cdcd52d4SBartosz Sobczak 		/* if level1_only, only go through it once */
52335105900SBartosz Sobczak 		if (!status || lvl == PBLE_LEVEL_1)
524cdcd52d4SBartosz Sobczak 			break;
525cdcd52d4SBartosz Sobczak 	}
526cdcd52d4SBartosz Sobczak 
527cdcd52d4SBartosz Sobczak exit:
528cdcd52d4SBartosz Sobczak 	if (!status) {
529cdcd52d4SBartosz Sobczak 		pble_rsrc->allocdpbles += pble_cnt;
530cdcd52d4SBartosz Sobczak 		pble_rsrc->stats_alloc_ok++;
531cdcd52d4SBartosz Sobczak 	} else {
532cdcd52d4SBartosz Sobczak 		pble_rsrc->stats_alloc_fail++;
533cdcd52d4SBartosz Sobczak 	}
534cdcd52d4SBartosz Sobczak 	mutex_unlock(&pble_rsrc->pble_mutex_lock);
535cdcd52d4SBartosz Sobczak 
536cdcd52d4SBartosz Sobczak 	return status;
537cdcd52d4SBartosz Sobczak }
538cdcd52d4SBartosz Sobczak 
539cdcd52d4SBartosz Sobczak /**
540cdcd52d4SBartosz Sobczak  * irdma_free_pble - put pbles back into prm
541cdcd52d4SBartosz Sobczak  * @pble_rsrc: pble resources
542cdcd52d4SBartosz Sobczak  * @palloc: contains all information regarding pble resource being freed
543cdcd52d4SBartosz Sobczak  */
544cdcd52d4SBartosz Sobczak void
irdma_free_pble(struct irdma_hmc_pble_rsrc * pble_rsrc,struct irdma_pble_alloc * palloc)545cdcd52d4SBartosz Sobczak irdma_free_pble(struct irdma_hmc_pble_rsrc *pble_rsrc,
546cdcd52d4SBartosz Sobczak 		struct irdma_pble_alloc *palloc)
547cdcd52d4SBartosz Sobczak {
548cdcd52d4SBartosz Sobczak 	pble_rsrc->freedpbles += palloc->total_cnt;
549cdcd52d4SBartosz Sobczak 
550cdcd52d4SBartosz Sobczak 	if (palloc->level == PBLE_LEVEL_2)
551cdcd52d4SBartosz Sobczak 		free_lvl2(pble_rsrc, palloc);
552cdcd52d4SBartosz Sobczak 	else
553cdcd52d4SBartosz Sobczak 		irdma_prm_return_pbles(&pble_rsrc->pinfo,
554cdcd52d4SBartosz Sobczak 				       &palloc->level1.chunkinfo);
555cdcd52d4SBartosz Sobczak 	pble_rsrc->stats_alloc_freed++;
556cdcd52d4SBartosz Sobczak }
557