1 /*-
2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD$
26 */
27
28 #include "opt_rss.h"
29 #include "opt_ratelimit.h"
30
31 #include <dev/mlx5/driver.h>
32 #include <dev/mlx5/device.h>
33 #include <dev/mlx5/mlx5_core/mlx5_core.h>
34
35 int mlx5_vsc_lock(struct mlx5_core_dev *mdev)
36 {
37 device_t dev = mdev->pdev->dev.bsddev;
38 int vsc_addr = mdev->vsc_addr;
39 int retries = 0;
40 u32 lock_val;
41 u32 counter;
42
43 if (!vsc_addr) {
44 mlx5_core_warn(mdev, "Unable to acquire vsc lock, vsc_addr not initialized\n");
45 return EINVAL;
46 }
47
48 while (true) {
49 if (retries > MLX5_VSC_MAX_RETRIES)
50 return EBUSY;
51
52 if (pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4)) {
53 retries++;
54 /*
55 * The PRM suggests random 0 - 10ms to prevent multiple
56 * waiters on the same interval in order to avoid starvation
57 */
58 DELAY((random() % 9000) + 1000);
59 continue;
60 }
61
62 counter = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4);
63 pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, counter, 4);
64 lock_val = pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4);
65
66 if (lock_val == counter)
67 break;
68
69 retries++;
70 }
71
72 return 0;
73 }
74
75 void mlx5_vsc_unlock(struct mlx5_core_dev *mdev)
76 {
77 device_t dev = mdev->pdev->dev.bsddev;
78 int vsc_addr = mdev->vsc_addr;
79
80 if (!vsc_addr) {
81 mlx5_core_warn(mdev, "Unable to release vsc lock, vsc_addr not initialized\n");
82 return;
83 }
84
85 pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 0, 4);
86 }
87
88 int
89 mlx5_vsc_wait_on_flag(struct mlx5_core_dev *mdev, u32 expected)
90 {
91 device_t dev = mdev->pdev->dev.bsddev;
92 int vsc_addr = mdev->vsc_addr;
93 int retries = 0;
94 u32 flag;
95
96 while (true) {
97 if (retries > MLX5_VSC_MAX_RETRIES)
98 return EBUSY;
99
100 flag = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4);
101 if (expected == MLX5_VSC_GET(vsc_addr, &flag, flag))
102 break;
103
104 retries++;
105 DELAY((random() % 90) + 10);
106 }
107
108 return 0;
109 }
110
111 int mlx5_vsc_set_space(struct mlx5_core_dev *mdev, u16 space)
112 {
113 device_t dev = mdev->pdev->dev.bsddev;
114 int vsc_addr = mdev->vsc_addr;
115 u32 vsc_space = 0;
116
117 if (!vsc_addr) {
118 mlx5_core_warn(mdev, "Unable to set vsc space, vsc_addr not initialized\n");
119 return EINVAL;
120 }
121
122 MLX5_VSC_SET(vsc_space, &vsc_space, space, space);
123 pci_write_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, vsc_space, 4);
124 vsc_space = pci_read_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, 4);
125
126 if (MLX5_VSC_GET(vsc_space, &vsc_space, status) != MLX5_VSC_SPACE_SUPPORTED) {
127 mlx5_core_warn(mdev, "Space 0x%x is not supported.\n", space);
128 return ENOTSUP;
129 }
130
131 return 0;
132 }
133
134 int mlx5_vsc_write(struct mlx5_core_dev *mdev, u32 addr, const u32 *data)
135 {
136 device_t dev = mdev->pdev->dev.bsddev;
137 int vsc_addr = mdev->vsc_addr;
138 u32 in = 0;
139 int err;
140
141 if (!vsc_addr) {
142 mlx5_core_warn(mdev, "Unable to call vsc write, vsc_addr not initialized\n");
143 return EINVAL;
144 }
145
146 MLX5_VSC_SET(vsc_addr, &in, address, addr);
147 MLX5_VSC_SET(vsc_addr, &in, flag, 1);
148 pci_write_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, *data, 4);
149 pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
150
151 err = mlx5_vsc_wait_on_flag(mdev, 0);
152 if (err)
153 mlx5_core_warn(mdev, "Failed waiting for write flag!\n");
154
155 return err;
156 }
157
158 int mlx5_vsc_read(struct mlx5_core_dev *mdev, u32 addr, u32 *data)
159 {
160 device_t dev = mdev->pdev->dev.bsddev;
161 int vsc_addr = mdev->vsc_addr;
162 int err;
163 u32 in;
164
165 if (!vsc_addr) {
166 mlx5_core_warn(mdev, "Unable to call vsc read, vsc_addr not initialized\n");
167 return EINVAL;
168 }
169
170 MLX5_VSC_SET(vsc_addr, &in, address, addr);
171 pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
172
173 err = mlx5_vsc_wait_on_flag(mdev, 1);
174 if (err) {
175 mlx5_core_warn(mdev, "Failed waiting for read complete flag!\n");
176 return err;
177 }
178
179 *data = pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4);
180
181 return 0;
182 }
183
184 int mlx5_vsc_lock_addr_space(struct mlx5_core_dev *mdev, u32 addr)
185 {
186 device_t dev = mdev->pdev->dev.bsddev;
187 int vsc_addr = mdev->vsc_addr;
188 u32 data;
189 int ret;
190 u32 id;
191
192 ret = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_SEMAPHORES);
193 if (ret)
194 return ret;
195
196 /* Get a unique ID based on the counter */
197 id = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4);
198
199 /* Try to modify lock */
200 ret = mlx5_vsc_write(mdev, addr, &id);
201 if (ret)
202 return ret;
203
204 /* Verify */
205 ret = mlx5_vsc_read(mdev, addr, &data);
206 if (ret)
207 return ret;
208 if (data != id)
209 return EBUSY;
210
211 return 0;
212 }
213
214 int mlx5_vsc_unlock_addr_space(struct mlx5_core_dev *mdev, u32 addr)
215 {
216 u32 data = 0;
217 int ret;
218
219 ret = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_SEMAPHORES);
220 if (ret)
221 return ret;
222
223 /* Try to modify lock */
224 ret = mlx5_vsc_write(mdev, addr, &data);
225 if (ret)
226 return ret;
227
228 /* Verify */
229 ret = mlx5_vsc_read(mdev, addr, &data);
230 if (ret)
231 return ret;
232 if (data != 0)
233 return EBUSY;
234
235 return 0;
236 }
237
238 int mlx5_vsc_find_cap(struct mlx5_core_dev *mdev)
239 {
240 int *capreg = &mdev->vsc_addr;
241 int err;
242
243 err = pci_find_cap(mdev->pdev->dev.bsddev, PCIY_VENDOR, capreg);
244
245 if (err)
246 *capreg = 0;
247
248 return err;
249 }
250
Cache object: 1291e617b01875334faf5357069e55b4
|