]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_core/mlx5_vsc.c
MFV r336490:
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_core / mlx5_vsc.c
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 <dev/mlx5/driver.h>
29 #include <dev/mlx5/device.h>
30 #include <dev/mlx5/mlx5_core/mlx5_core.h>
31
32 #define MLX5_SEMAPHORE_SPACE_DOMAIN 0xA
33
34 struct mlx5_ifc_vsc_space_bits {
35         u8 status[0x3];
36         u8 reserved0[0xd];
37         u8 space[0x10];
38 };
39
40 struct mlx5_ifc_vsc_addr_bits {
41         u8 flag[0x1];
42         u8 reserved0[0x1];
43         u8 address[0x1e];
44 };
45
46 int mlx5_vsc_lock(struct mlx5_core_dev *mdev)
47 {
48         device_t dev = mdev->pdev->dev.bsddev;
49         int vsc_addr = mdev->vsc_addr;
50         int retries = 0;
51         u32 lock_val;
52         u32 counter;
53
54         if (!vsc_addr) {
55                 mlx5_core_warn(mdev, "Unable to acquire vsc lock, vsc_addr not initialized\n");
56                 return EINVAL;
57         }
58
59         while (true) {
60                 if (retries > MLX5_VSC_MAX_RETRIES)
61                         return EBUSY;
62
63                 if (pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4)) {
64                         retries++;
65                         /*
66                          * The PRM suggests random 0 - 10ms to prevent multiple
67                          * waiters on the same interval in order to avoid starvation
68                          */
69                         DELAY((random() % 11) * 1000);
70                         continue;
71                 }
72
73                 counter = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4);
74                 pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, counter, 4);
75                 lock_val = pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4);
76
77                 if (lock_val == counter)
78                         break;
79
80                 retries++;
81         }
82
83         return 0;
84 }
85
86 void mlx5_vsc_unlock(struct mlx5_core_dev *mdev)
87 {
88         device_t dev = mdev->pdev->dev.bsddev;
89         int vsc_addr = mdev->vsc_addr;
90
91         if (!vsc_addr) {
92                 mlx5_core_warn(mdev, "Unable to release vsc lock, vsc_addr not initialized\n");
93                 return;
94         }
95
96         pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 0, 4);
97 }
98
99 static int mlx5_vsc_wait_on_flag(struct mlx5_core_dev *mdev, u32 expected)
100 {
101         device_t dev = mdev->pdev->dev.bsddev;
102         int vsc_addr = mdev->vsc_addr;
103         int retries = 0;
104         u32 flag;
105
106         while (true) {
107                 if (retries > MLX5_VSC_MAX_RETRIES)
108                         return EBUSY;
109
110                 flag = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4);
111                 if (expected == MLX5_VSC_GET(vsc_addr, &flag, flag))
112                         break;
113
114                 retries++;
115                 DELAY(10);
116         }
117
118         return 0;
119 }
120
121 int mlx5_vsc_set_space(struct mlx5_core_dev *mdev, u16 space)
122 {
123         device_t dev = mdev->pdev->dev.bsddev;
124         int vsc_addr = mdev->vsc_addr;
125         u32 vsc_space = 0;
126
127         if (!vsc_addr) {
128                 mlx5_core_warn(mdev, "Unable to set vsc space, vsc_addr not initialized\n");
129                 return EINVAL;
130         }
131
132         MLX5_VSC_SET(vsc_space, &vsc_space, space, space);
133         pci_write_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, vsc_space, 4);
134         vsc_space = pci_read_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, 4);
135
136         if (MLX5_VSC_GET(vsc_space, &vsc_space, status) != MLX5_VSC_SPACE_SUPPORTED) {
137                 mlx5_core_warn(mdev, "Space 0x%x is not supported.\n", space);
138                 return ENOTSUP;
139         }
140
141         return 0;
142 }
143
144 int mlx5_vsc_write(struct mlx5_core_dev *mdev, u32 addr, const u32 *data)
145 {
146         device_t dev = mdev->pdev->dev.bsddev;
147         int vsc_addr = mdev->vsc_addr;
148         u32 in = 0;
149         int err;
150
151         if (!vsc_addr) {
152                 mlx5_core_warn(mdev, "Unable to call vsc write, vsc_addr not initialized\n");
153                 return EINVAL;
154         }
155
156         MLX5_VSC_SET(vsc_addr, &in, address, addr);
157         MLX5_VSC_SET(vsc_addr, &in, flag, 1);
158         pci_write_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, *data, 4);
159         pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
160
161         err = mlx5_vsc_wait_on_flag(mdev, 0);
162         if (err)
163                 mlx5_core_warn(mdev, "Failed waiting for write flag!\n");
164
165         return err;
166 }
167
168 int mlx5_vsc_read(struct mlx5_core_dev *mdev, u32 addr, u32 *data)
169 {
170         device_t dev = mdev->pdev->dev.bsddev;
171         int vsc_addr = mdev->vsc_addr;
172         int err;
173         u32 in;
174
175         if (!vsc_addr) {
176                 mlx5_core_warn(mdev, "Unable to call vsc read, vsc_addr not initialized\n");
177                 return EINVAL;
178         }
179
180         MLX5_VSC_SET(vsc_addr, &in, address, addr);
181         pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
182
183         err = mlx5_vsc_wait_on_flag(mdev, 1);
184         if (err) {
185                 mlx5_core_warn(mdev, "Failed waiting for read complete flag!\n");
186                 return err;
187         }
188
189         *data = pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4);
190
191         return 0;
192 }
193
194 int mlx5_vsc_lock_addr_space(struct mlx5_core_dev *mdev, u32 addr)
195 {
196         device_t dev = mdev->pdev->dev.bsddev;
197         int vsc_addr = mdev->vsc_addr;
198         u32 data;
199         int ret;
200         u32 id;
201
202         ret = mlx5_vsc_set_space(mdev, MLX5_SEMAPHORE_SPACE_DOMAIN);
203         if (ret)
204                 return ret;
205
206         /* Get a unique ID based on the counter */
207         id = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4);
208
209         /* Try to modify lock */
210         ret = mlx5_vsc_write(mdev, addr, &id);
211         if (ret)
212                 return ret;
213
214         /* Verify */
215         ret = mlx5_vsc_read(mdev, addr, &data);
216         if (ret)
217                 return ret;
218         if (data != id)
219                 return EBUSY;
220
221         return 0;
222 }
223
224 int mlx5_vsc_unlock_addr_space(struct mlx5_core_dev *mdev, u32 addr)
225 {
226         u32 data = 0;
227         int ret;
228
229         ret = mlx5_vsc_set_space(mdev, MLX5_SEMAPHORE_SPACE_DOMAIN);
230         if (ret)
231                 return ret;
232
233         /* Try to modify lock */
234         ret = mlx5_vsc_write(mdev, addr, &data);
235         if (ret)
236                 return ret;
237
238         /* Verify */
239         ret = mlx5_vsc_read(mdev, addr, &data);
240         if (ret)
241                 return ret;
242         if (data != 0)
243                 return EBUSY;
244
245         return 0;
246 }
247
248 int mlx5_vsc_find_cap(struct mlx5_core_dev *mdev)
249 {
250         int *capreg = &mdev->vsc_addr;
251         int err;
252
253         err = pci_find_cap(mdev->pdev->dev.bsddev, PCIY_VENDOR, capreg);
254
255         if (err)
256                 *capreg = 0;
257
258         return err;
259 }
260