net/mlx5: PD and UAR commands via mlx5 ifc
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / uar.c
1 /*
2  * Copyright (c) 2013-2015, Mellanox Technologies. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32
33 #include <linux/kernel.h>
34 #include <linux/module.h>
35 #include <linux/io-mapping.h>
36 #include <linux/mlx5/driver.h>
37 #include <linux/mlx5/cmd.h>
38 #include "mlx5_core.h"
39
40 enum {
41         NUM_DRIVER_UARS         = 4,
42         NUM_LOW_LAT_UUARS       = 4,
43 };
44
45 int mlx5_cmd_alloc_uar(struct mlx5_core_dev *dev, u32 *uarn)
46 {
47         u32 out[MLX5_ST_SZ_DW(alloc_uar_out)] = {0};
48         u32 in[MLX5_ST_SZ_DW(alloc_uar_in)]   = {0};
49         int err;
50
51         MLX5_SET(alloc_uar_in, in, opcode, MLX5_CMD_OP_ALLOC_UAR);
52         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
53         err = err ? : mlx5_cmd_status_to_err_v2(out);
54         if (err)
55                 return err;
56
57         *uarn = MLX5_GET(alloc_uar_out, out, uar);
58         return err;
59 }
60 EXPORT_SYMBOL(mlx5_cmd_alloc_uar);
61
62 int mlx5_cmd_free_uar(struct mlx5_core_dev *dev, u32 uarn)
63 {
64         u32 out[MLX5_ST_SZ_DW(dealloc_uar_out)] = {0};
65         u32 in[MLX5_ST_SZ_DW(dealloc_uar_in)]   = {0};
66         int err;
67
68         MLX5_SET(dealloc_uar_in, in, opcode, MLX5_CMD_OP_DEALLOC_UAR);
69         MLX5_SET(dealloc_uar_in, in, uar, uarn);
70         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
71         return err ? : mlx5_cmd_status_to_err_v2(out);
72 }
73 EXPORT_SYMBOL(mlx5_cmd_free_uar);
74
75 static int need_uuar_lock(int uuarn)
76 {
77         int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE;
78
79         if (uuarn == 0 || tot_uuars - NUM_LOW_LAT_UUARS)
80                 return 0;
81
82         return 1;
83 }
84
85 int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
86 {
87         int tot_uuars = NUM_DRIVER_UARS * MLX5_BF_REGS_PER_PAGE;
88         struct mlx5_bf *bf;
89         phys_addr_t addr;
90         int err;
91         int i;
92
93         uuari->num_uars = NUM_DRIVER_UARS;
94         uuari->num_low_latency_uuars = NUM_LOW_LAT_UUARS;
95
96         mutex_init(&uuari->lock);
97         uuari->uars = kcalloc(uuari->num_uars, sizeof(*uuari->uars), GFP_KERNEL);
98         if (!uuari->uars)
99                 return -ENOMEM;
100
101         uuari->bfs = kcalloc(tot_uuars, sizeof(*uuari->bfs), GFP_KERNEL);
102         if (!uuari->bfs) {
103                 err = -ENOMEM;
104                 goto out_uars;
105         }
106
107         uuari->bitmap = kcalloc(BITS_TO_LONGS(tot_uuars), sizeof(*uuari->bitmap),
108                                 GFP_KERNEL);
109         if (!uuari->bitmap) {
110                 err = -ENOMEM;
111                 goto out_bfs;
112         }
113
114         uuari->count = kcalloc(tot_uuars, sizeof(*uuari->count), GFP_KERNEL);
115         if (!uuari->count) {
116                 err = -ENOMEM;
117                 goto out_bitmap;
118         }
119
120         for (i = 0; i < uuari->num_uars; i++) {
121                 err = mlx5_cmd_alloc_uar(dev, &uuari->uars[i].index);
122                 if (err)
123                         goto out_count;
124
125                 addr = dev->iseg_base + ((phys_addr_t)(uuari->uars[i].index) << PAGE_SHIFT);
126                 uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
127                 if (!uuari->uars[i].map) {
128                         mlx5_cmd_free_uar(dev, uuari->uars[i].index);
129                         err = -ENOMEM;
130                         goto out_count;
131                 }
132                 mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
133                               uuari->uars[i].index, uuari->uars[i].map);
134         }
135
136         for (i = 0; i < tot_uuars; i++) {
137                 bf = &uuari->bfs[i];
138
139                 bf->buf_size = (1 << MLX5_CAP_GEN(dev, log_bf_reg_size)) / 2;
140                 bf->uar = &uuari->uars[i / MLX5_BF_REGS_PER_PAGE];
141                 bf->regreg = uuari->uars[i / MLX5_BF_REGS_PER_PAGE].map;
142                 bf->reg = NULL; /* Add WC support */
143                 bf->offset = (i % MLX5_BF_REGS_PER_PAGE) *
144                              (1 << MLX5_CAP_GEN(dev, log_bf_reg_size)) +
145                              MLX5_BF_OFFSET;
146                 bf->need_lock = need_uuar_lock(i);
147                 spin_lock_init(&bf->lock);
148                 spin_lock_init(&bf->lock32);
149                 bf->uuarn = i;
150         }
151
152         return 0;
153
154 out_count:
155         for (i--; i >= 0; i--) {
156                 iounmap(uuari->uars[i].map);
157                 mlx5_cmd_free_uar(dev, uuari->uars[i].index);
158         }
159         kfree(uuari->count);
160
161 out_bitmap:
162         kfree(uuari->bitmap);
163
164 out_bfs:
165         kfree(uuari->bfs);
166
167 out_uars:
168         kfree(uuari->uars);
169         return err;
170 }
171
172 int mlx5_free_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
173 {
174         int i = uuari->num_uars;
175
176         for (i--; i >= 0; i--) {
177                 iounmap(uuari->uars[i].map);
178                 mlx5_cmd_free_uar(dev, uuari->uars[i].index);
179         }
180
181         kfree(uuari->count);
182         kfree(uuari->bitmap);
183         kfree(uuari->bfs);
184         kfree(uuari->uars);
185
186         return 0;
187 }
188
189 int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar,
190                        bool map_wc)
191 {
192         phys_addr_t pfn;
193         phys_addr_t uar_bar_start;
194         int err;
195
196         err = mlx5_cmd_alloc_uar(mdev, &uar->index);
197         if (err) {
198                 mlx5_core_warn(mdev, "mlx5_cmd_alloc_uar() failed, %d\n", err);
199                 return err;
200         }
201
202         uar_bar_start = pci_resource_start(mdev->pdev, 0);
203         pfn           = (uar_bar_start >> PAGE_SHIFT) + uar->index;
204
205         if (map_wc) {
206                 uar->bf_map = ioremap_wc(pfn << PAGE_SHIFT, PAGE_SIZE);
207                 if (!uar->bf_map) {
208                         mlx5_core_warn(mdev, "ioremap_wc() failed\n");
209                         uar->map = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
210                         if (!uar->map)
211                                 goto err_free_uar;
212                 }
213         } else {
214                 uar->map = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
215                 if (!uar->map)
216                         goto err_free_uar;
217         }
218
219         return 0;
220
221 err_free_uar:
222         mlx5_core_warn(mdev, "ioremap() failed\n");
223         err = -ENOMEM;
224         mlx5_cmd_free_uar(mdev, uar->index);
225
226         return err;
227 }
228 EXPORT_SYMBOL(mlx5_alloc_map_uar);
229
230 void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar)
231 {
232         if (uar->map)
233                 iounmap(uar->map);
234         else
235                 iounmap(uar->bf_map);
236         mlx5_cmd_free_uar(mdev, uar->index);
237 }
238 EXPORT_SYMBOL(mlx5_unmap_free_uar);