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