xref: /freebsd-src/sys/dev/mlx5/mlx5_core/mlx5_alloc.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
1dc7e38acSHans Petter Selasky /*-
21c807f67SHans Petter Selasky  * Copyright (c) 2013-2017, Mellanox Technologies, Ltd.  All rights reserved.
3dc7e38acSHans Petter Selasky  *
4dc7e38acSHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
5dc7e38acSHans Petter Selasky  * modification, are permitted provided that the following conditions
6dc7e38acSHans Petter Selasky  * are met:
7dc7e38acSHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
8dc7e38acSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer.
9dc7e38acSHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
10dc7e38acSHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
11dc7e38acSHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
12dc7e38acSHans Petter Selasky  *
13dc7e38acSHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14dc7e38acSHans Petter Selasky  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15dc7e38acSHans Petter Selasky  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16dc7e38acSHans Petter Selasky  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17dc7e38acSHans Petter Selasky  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18dc7e38acSHans Petter Selasky  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19dc7e38acSHans Petter Selasky  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20dc7e38acSHans Petter Selasky  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21dc7e38acSHans Petter Selasky  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22dc7e38acSHans Petter Selasky  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23dc7e38acSHans Petter Selasky  * SUCH DAMAGE.
24dc7e38acSHans Petter Selasky  */
25dc7e38acSHans Petter Selasky 
26ee9d634bSKonstantin Belousov #include "opt_rss.h"
27ee9d634bSKonstantin Belousov #include "opt_ratelimit.h"
28ee9d634bSKonstantin Belousov 
29dc7e38acSHans Petter Selasky #include <linux/errno.h>
30dc7e38acSHans Petter Selasky #include <linux/slab.h>
31dc7e38acSHans Petter Selasky #include <linux/mm.h>
32dc7e38acSHans Petter Selasky #include <linux/dma-mapping.h>
33dc7e38acSHans Petter Selasky #include <linux/vmalloc.h>
34dc7e38acSHans Petter Selasky #include <dev/mlx5/driver.h>
35*12c56d7dSHans Petter Selasky #include <dev/mlx5/mlx5_core/mlx5_core.h>
36dc7e38acSHans Petter Selasky 
37dc7e38acSHans Petter Selasky /* Handling for queue buffers -- we allocate a bunch of memory and
38dc7e38acSHans Petter Selasky  * register it in a memory region at HCA virtual address 0.  If the
39dc7e38acSHans Petter Selasky  * requested size is > max_direct, we split the allocation into
40dc7e38acSHans Petter Selasky  * multiple pages, so we don't require too much contiguous memory.
41dc7e38acSHans Petter Selasky  */
42dc7e38acSHans Petter Selasky 
431c807f67SHans Petter Selasky static void
mlx5_buf_load_mem_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)441c807f67SHans Petter Selasky mlx5_buf_load_mem_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
45dc7e38acSHans Petter Selasky {
461c807f67SHans Petter Selasky 	struct mlx5_buf *buf;
471c807f67SHans Petter Selasky 	uint8_t owned;
481c807f67SHans Petter Selasky 	int x;
49dc7e38acSHans Petter Selasky 
501c807f67SHans Petter Selasky 	buf = (struct mlx5_buf *)arg;
511c807f67SHans Petter Selasky 	owned = MLX5_DMA_OWNED(buf->dev);
521c807f67SHans Petter Selasky 
531c807f67SHans Petter Selasky 	if (!owned)
541c807f67SHans Petter Selasky 		MLX5_DMA_LOCK(buf->dev);
551c807f67SHans Petter Selasky 
561c807f67SHans Petter Selasky 	if (error == 0) {
571c807f67SHans Petter Selasky 		for (x = 0; x != nseg; x++) {
581c807f67SHans Petter Selasky 			buf->page_list[x] = segs[x].ds_addr;
591c807f67SHans Petter Selasky 			KASSERT(segs[x].ds_len == PAGE_SIZE, ("Invalid segment size"));
60dc7e38acSHans Petter Selasky 		}
611c807f67SHans Petter Selasky 		buf->load_done = MLX5_LOAD_ST_SUCCESS;
62dc7e38acSHans Petter Selasky 	} else {
631c807f67SHans Petter Selasky 		buf->load_done = MLX5_LOAD_ST_FAILURE;
641c807f67SHans Petter Selasky 	}
651c807f67SHans Petter Selasky 	MLX5_DMA_DONE(buf->dev);
66dc7e38acSHans Petter Selasky 
671c807f67SHans Petter Selasky 	if (!owned)
681c807f67SHans Petter Selasky 		MLX5_DMA_UNLOCK(buf->dev);
69dc7e38acSHans Petter Selasky }
70dc7e38acSHans Petter Selasky 
711c807f67SHans Petter Selasky int
mlx5_buf_alloc(struct mlx5_core_dev * dev,int size,int max_direct,struct mlx5_buf * buf)721c807f67SHans Petter Selasky mlx5_buf_alloc(struct mlx5_core_dev *dev, int size,
731c807f67SHans Petter Selasky     int max_direct, struct mlx5_buf *buf)
74dc7e38acSHans Petter Selasky {
751c807f67SHans Petter Selasky 	int err;
76dc7e38acSHans Petter Selasky 
771c807f67SHans Petter Selasky 	buf->npages = howmany(size, PAGE_SIZE);
781c807f67SHans Petter Selasky 	buf->page_shift = PAGE_SHIFT;
791c807f67SHans Petter Selasky 	buf->load_done = MLX5_LOAD_ST_NONE;
801c807f67SHans Petter Selasky 	buf->dev = dev;
811c807f67SHans Petter Selasky 	buf->page_list = kcalloc(buf->npages, sizeof(*buf->page_list),
821c807f67SHans Petter Selasky 	    GFP_KERNEL);
831c807f67SHans Petter Selasky 
841c807f67SHans Petter Selasky 	err = -bus_dma_tag_create(
851c807f67SHans Petter Selasky 	    bus_get_dma_tag(dev->pdev->dev.bsddev),
861c807f67SHans Petter Selasky 	    PAGE_SIZE,		/* alignment */
871c807f67SHans Petter Selasky 	    0,			/* no boundary */
881c807f67SHans Petter Selasky 	    BUS_SPACE_MAXADDR,	/* lowaddr */
891c807f67SHans Petter Selasky 	    BUS_SPACE_MAXADDR,	/* highaddr */
901c807f67SHans Petter Selasky 	    NULL, NULL,		/* filter, filterarg */
911c807f67SHans Petter Selasky 	    PAGE_SIZE * buf->npages,	/* maxsize */
921c807f67SHans Petter Selasky 	    buf->npages,	/* nsegments */
931c807f67SHans Petter Selasky 	    PAGE_SIZE,		/* maxsegsize */
941c807f67SHans Petter Selasky 	    0,			/* flags */
951c807f67SHans Petter Selasky 	    NULL, NULL,		/* lockfunc, lockfuncarg */
961c807f67SHans Petter Selasky 	    &buf->dma_tag);
971c807f67SHans Petter Selasky 
981c807f67SHans Petter Selasky 	if (err != 0)
991c807f67SHans Petter Selasky 		goto err_dma_tag;
1001c807f67SHans Petter Selasky 
1011c807f67SHans Petter Selasky 	/* allocate memory */
1021c807f67SHans Petter Selasky 	err = -bus_dmamem_alloc(buf->dma_tag, &buf->direct.buf,
1031c807f67SHans Petter Selasky 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &buf->dma_map);
1041c807f67SHans Petter Selasky 	if (err != 0)
1051c807f67SHans Petter Selasky 		goto err_dma_alloc;
1061c807f67SHans Petter Selasky 
1071c807f67SHans Petter Selasky 	/* load memory into DMA */
1081c807f67SHans Petter Selasky 	MLX5_DMA_LOCK(dev);
1091c807f67SHans Petter Selasky 	err = bus_dmamap_load(
1101c807f67SHans Petter Selasky 	    buf->dma_tag, buf->dma_map, buf->direct.buf,
1111c807f67SHans Petter Selasky 	    PAGE_SIZE * buf->npages, &mlx5_buf_load_mem_cb,
1121c807f67SHans Petter Selasky 	    buf, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
1131c807f67SHans Petter Selasky 
1141c807f67SHans Petter Selasky 	while (buf->load_done == MLX5_LOAD_ST_NONE)
1151c807f67SHans Petter Selasky 		MLX5_DMA_WAIT(dev);
1161c807f67SHans Petter Selasky 	MLX5_DMA_UNLOCK(dev);
1171c807f67SHans Petter Selasky 
1181c807f67SHans Petter Selasky 	/* check for error */
1191c807f67SHans Petter Selasky 	if (buf->load_done != MLX5_LOAD_ST_SUCCESS) {
1201c807f67SHans Petter Selasky 		err = -ENOMEM;
1211c807f67SHans Petter Selasky 		goto err_dma_load;
1221c807f67SHans Petter Selasky 	}
1231c807f67SHans Petter Selasky 
1241c807f67SHans Petter Selasky 	/* clean memory */
1251c807f67SHans Petter Selasky 	memset(buf->direct.buf, 0, PAGE_SIZE * buf->npages);
1261c807f67SHans Petter Selasky 
1271c807f67SHans Petter Selasky 	/* flush memory to RAM */
1281c807f67SHans Petter Selasky 	bus_dmamap_sync(buf->dev->cmd.dma_tag, buf->dma_map, BUS_DMASYNC_PREWRITE);
1291c807f67SHans Petter Selasky 	return (0);
1301c807f67SHans Petter Selasky 
1311c807f67SHans Petter Selasky err_dma_load:
1321c807f67SHans Petter Selasky 	bus_dmamem_free(buf->dma_tag, buf->direct.buf, buf->dma_map);
1331c807f67SHans Petter Selasky err_dma_alloc:
1341c807f67SHans Petter Selasky 	bus_dma_tag_destroy(buf->dma_tag);
1351c807f67SHans Petter Selasky err_dma_tag:
1361c807f67SHans Petter Selasky 	kfree(buf->page_list);
1371c807f67SHans Petter Selasky 	return (err);
1381c807f67SHans Petter Selasky }
139dc7e38acSHans Petter Selasky 
mlx5_buf_free(struct mlx5_core_dev * dev,struct mlx5_buf * buf)140dc7e38acSHans Petter Selasky void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf)
141dc7e38acSHans Petter Selasky {
142dc7e38acSHans Petter Selasky 
1431c807f67SHans Petter Selasky 	bus_dmamap_unload(buf->dma_tag, buf->dma_map);
1441c807f67SHans Petter Selasky 	bus_dmamem_free(buf->dma_tag, buf->direct.buf, buf->dma_map);
1451c807f67SHans Petter Selasky 	bus_dma_tag_destroy(buf->dma_tag);
146dc7e38acSHans Petter Selasky 	kfree(buf->page_list);
147dc7e38acSHans Petter Selasky }
148dc7e38acSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx5_buf_free);
149dc7e38acSHans Petter Selasky 
mlx5_alloc_db_pgdir(struct mlx5_core_dev * dev)1507c3eff94SHans Petter Selasky static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev)
151dc7e38acSHans Petter Selasky {
152dc7e38acSHans Petter Selasky 	struct mlx5_db_pgdir *pgdir;
153dc7e38acSHans Petter Selasky 
154dc7e38acSHans Petter Selasky 	pgdir = kzalloc(sizeof(*pgdir), GFP_KERNEL);
155dc7e38acSHans Petter Selasky 
156dc7e38acSHans Petter Selasky 	bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE);
157dc7e38acSHans Petter Selasky 
1581c807f67SHans Petter Selasky 	pgdir->fw_page = mlx5_fwp_alloc(dev, GFP_KERNEL, 1);
1591c807f67SHans Petter Selasky 	if (pgdir->fw_page != NULL) {
1601c807f67SHans Petter Selasky 		pgdir->db_page = pgdir->fw_page->virt_addr;
1611c807f67SHans Petter Selasky 		pgdir->db_dma = pgdir->fw_page->dma_addr;
1621c807f67SHans Petter Selasky 
1631c807f67SHans Petter Selasky 		/* clean allocated memory */
1641c807f67SHans Petter Selasky 		memset(pgdir->db_page, 0, MLX5_ADAPTER_PAGE_SIZE);
1651c807f67SHans Petter Selasky 
1661c807f67SHans Petter Selasky 		/* flush memory to RAM */
1671c807f67SHans Petter Selasky 		mlx5_fwp_flush(pgdir->fw_page);
1681c807f67SHans Petter Selasky 	}
169dc7e38acSHans Petter Selasky 	if (!pgdir->db_page) {
170dc7e38acSHans Petter Selasky 		kfree(pgdir);
171dc7e38acSHans Petter Selasky 		return NULL;
172dc7e38acSHans Petter Selasky 	}
173dc7e38acSHans Petter Selasky 
174dc7e38acSHans Petter Selasky 	return pgdir;
175dc7e38acSHans Petter Selasky }
176dc7e38acSHans Petter Selasky 
mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir * pgdir,struct mlx5_db * db)177dc7e38acSHans Petter Selasky static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir,
178dc7e38acSHans Petter Selasky 				    struct mlx5_db *db)
179dc7e38acSHans Petter Selasky {
180dc7e38acSHans Petter Selasky 	int offset;
181dc7e38acSHans Petter Selasky 	int i;
182dc7e38acSHans Petter Selasky 
183dc7e38acSHans Petter Selasky 	i = find_first_bit(pgdir->bitmap, MLX5_DB_PER_PAGE);
184dc7e38acSHans Petter Selasky 	if (i >= MLX5_DB_PER_PAGE)
185dc7e38acSHans Petter Selasky 		return -ENOMEM;
186dc7e38acSHans Petter Selasky 
187dc7e38acSHans Petter Selasky 	__clear_bit(i, pgdir->bitmap);
188dc7e38acSHans Petter Selasky 
189dc7e38acSHans Petter Selasky 	db->u.pgdir = pgdir;
190dc7e38acSHans Petter Selasky 	db->index   = i;
191dc7e38acSHans Petter Selasky 	offset = db->index * L1_CACHE_BYTES;
192dc7e38acSHans Petter Selasky 	db->db      = pgdir->db_page + offset / sizeof(*pgdir->db_page);
193dc7e38acSHans Petter Selasky 	db->dma     = pgdir->db_dma  + offset;
194dc7e38acSHans Petter Selasky 
195dc7e38acSHans Petter Selasky 	db->db[0] = 0;
196dc7e38acSHans Petter Selasky 	db->db[1] = 0;
197dc7e38acSHans Petter Selasky 
198dc7e38acSHans Petter Selasky 	return 0;
199dc7e38acSHans Petter Selasky }
200dc7e38acSHans Petter Selasky 
mlx5_db_alloc(struct mlx5_core_dev * dev,struct mlx5_db * db)2017c3eff94SHans Petter Selasky int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db)
202dc7e38acSHans Petter Selasky {
203dc7e38acSHans Petter Selasky 	struct mlx5_db_pgdir *pgdir;
204dc7e38acSHans Petter Selasky 	int ret = 0;
205dc7e38acSHans Petter Selasky 
206dc7e38acSHans Petter Selasky 	mutex_lock(&dev->priv.pgdir_mutex);
207dc7e38acSHans Petter Selasky 
208dc7e38acSHans Petter Selasky 	list_for_each_entry(pgdir, &dev->priv.pgdir_list, list)
209dc7e38acSHans Petter Selasky 		if (!mlx5_alloc_db_from_pgdir(pgdir, db))
210dc7e38acSHans Petter Selasky 			goto out;
211dc7e38acSHans Petter Selasky 
2127c3eff94SHans Petter Selasky 	pgdir = mlx5_alloc_db_pgdir(dev);
213dc7e38acSHans Petter Selasky 	if (!pgdir) {
214dc7e38acSHans Petter Selasky 		ret = -ENOMEM;
215dc7e38acSHans Petter Selasky 		goto out;
216dc7e38acSHans Petter Selasky 	}
217dc7e38acSHans Petter Selasky 
218dc7e38acSHans Petter Selasky 	list_add(&pgdir->list, &dev->priv.pgdir_list);
219dc7e38acSHans Petter Selasky 
220dc7e38acSHans Petter Selasky 	/* This should never fail -- we just allocated an empty page: */
221dc7e38acSHans Petter Selasky 	WARN_ON(mlx5_alloc_db_from_pgdir(pgdir, db));
222dc7e38acSHans Petter Selasky 
223dc7e38acSHans Petter Selasky out:
224dc7e38acSHans Petter Selasky 	mutex_unlock(&dev->priv.pgdir_mutex);
225dc7e38acSHans Petter Selasky 
226dc7e38acSHans Petter Selasky 	return ret;
227dc7e38acSHans Petter Selasky }
228dc7e38acSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx5_db_alloc);
229dc7e38acSHans Petter Selasky 
mlx5_db_free(struct mlx5_core_dev * dev,struct mlx5_db * db)230dc7e38acSHans Petter Selasky void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db)
231dc7e38acSHans Petter Selasky {
232dc7e38acSHans Petter Selasky 	mutex_lock(&dev->priv.pgdir_mutex);
233dc7e38acSHans Petter Selasky 
234dc7e38acSHans Petter Selasky 	__set_bit(db->index, db->u.pgdir->bitmap);
235dc7e38acSHans Petter Selasky 
236dc7e38acSHans Petter Selasky 	if (bitmap_full(db->u.pgdir->bitmap, MLX5_DB_PER_PAGE)) {
2371c807f67SHans Petter Selasky 		mlx5_fwp_free(db->u.pgdir->fw_page);
238dc7e38acSHans Petter Selasky 		list_del(&db->u.pgdir->list);
239dc7e38acSHans Petter Selasky 		kfree(db->u.pgdir);
240dc7e38acSHans Petter Selasky 	}
241dc7e38acSHans Petter Selasky 
242dc7e38acSHans Petter Selasky 	mutex_unlock(&dev->priv.pgdir_mutex);
243dc7e38acSHans Petter Selasky }
244dc7e38acSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx5_db_free);
245dc7e38acSHans Petter Selasky 
2461c807f67SHans Petter Selasky void
mlx5_fill_page_array(struct mlx5_buf * buf,__be64 * pas)2471c807f67SHans Petter Selasky mlx5_fill_page_array(struct mlx5_buf *buf, __be64 *pas)
248dc7e38acSHans Petter Selasky {
249dc7e38acSHans Petter Selasky 	int i;
250dc7e38acSHans Petter Selasky 
2511c807f67SHans Petter Selasky 	for (i = 0; i != buf->npages; i++)
2521c807f67SHans Petter Selasky 		pas[i] = cpu_to_be64(buf->page_list[i]);
253dc7e38acSHans Petter Selasky }
254dc7e38acSHans Petter Selasky EXPORT_SYMBOL_GPL(mlx5_fill_page_array);
255