]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_core/mlx5_vsc.c
Upgrade Unbound to 1.6.7. More to follow.
[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 struct mlx5_ifc_vsc_space_bits {
33         u8 status[0x3];
34         u8 reserved0[0xd];
35         u8 space[0x10];
36 };
37
38 struct mlx5_ifc_vsc_addr_bits {
39         u8 flag[0x1];
40         u8 reserved0[0x1];
41         u8 address[0x1e];
42 };
43
44 int mlx5_vsc_lock(struct mlx5_core_dev *mdev)
45 {
46         device_t dev = mdev->pdev->dev.bsddev;
47         int vsc_addr = mdev->vsc_addr;
48         int retries = 0;
49         u32 lock_val;
50         u32 counter;
51
52         if (!vsc_addr) {
53                 mlx5_core_warn(mdev, "Unable to acquire vsc lock, vsc_addr not initialized\n");
54                 return EINVAL;
55         }
56
57         while (true) {
58                 if (retries > MLX5_VSC_MAX_RETRIES)
59                         return EBUSY;
60
61                 if (pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4)) {
62                         retries++;
63                         /*
64                          * The PRM suggests random 0 - 10ms to prevent multiple
65                          * waiters on the same interval in order to avoid starvation
66                          */
67                         DELAY((random() % 11) * 1000);
68                         continue;
69                 }
70
71                 counter = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4);
72                 pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, counter, 4);
73                 lock_val = pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4);
74
75                 if (lock_val == counter)
76                         break;
77
78                 retries++;
79         }
80
81         return 0;
82 }
83
84 void mlx5_vsc_unlock(struct mlx5_core_dev *mdev)
85 {
86         device_t dev = mdev->pdev->dev.bsddev;
87         int vsc_addr = mdev->vsc_addr;
88
89         if (!vsc_addr) {
90                 mlx5_core_warn(mdev, "Unable to release vsc lock, vsc_addr not initialized\n");
91                 return;
92         }
93
94         pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 0, 4);
95 }
96
97 static int mlx5_vsc_wait_on_flag(struct mlx5_core_dev *mdev, u32 expected)
98 {
99         device_t dev = mdev->pdev->dev.bsddev;
100         int vsc_addr = mdev->vsc_addr;
101         int retries = 0;
102         u32 flag;
103
104         while (true) {
105                 if (retries > MLX5_VSC_MAX_RETRIES)
106                         return EBUSY;
107
108                 flag = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4);
109                 if (expected == MLX5_VSC_GET(vsc_addr, &flag, flag))
110                         break;
111
112                 retries++;
113                 DELAY(10);
114         }
115
116         return 0;
117 }
118
119 int mlx5_vsc_set_space(struct mlx5_core_dev *mdev, u16 space)
120 {
121         device_t dev = mdev->pdev->dev.bsddev;
122         int vsc_addr = mdev->vsc_addr;
123         u32 vsc_space = 0;
124
125         if (!vsc_addr) {
126                 mlx5_core_warn(mdev, "Unable to set vsc space, vsc_addr not initialized\n");
127                 return EINVAL;
128         }
129
130         MLX5_VSC_SET(vsc_space, &vsc_space, space, space);
131         pci_write_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, vsc_space, 4);
132         vsc_space = pci_read_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, 4);
133
134         if (MLX5_VSC_GET(vsc_space, &vsc_space, status) != MLX5_VSC_SPACE_SUPPORTED) {
135                 mlx5_core_warn(mdev, "Space 0x%x is not supported.\n", space);
136                 return ENOTSUP;
137         }
138
139         return 0;
140 }
141
142 int mlx5_vsc_write(struct mlx5_core_dev *mdev, u32 addr, u32 *data)
143 {
144         device_t dev = mdev->pdev->dev.bsddev;
145         int vsc_addr = mdev->vsc_addr;
146         u32 in = 0;
147         int err;
148
149         if (!vsc_addr) {
150                 mlx5_core_warn(mdev, "Unable to call vsc write, vsc_addr not initialized\n");
151                 return EINVAL;
152         }
153
154         MLX5_VSC_SET(vsc_addr, &in, address, addr);
155         MLX5_VSC_SET(vsc_addr, &in, flag, 1);
156         pci_write_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, *data, 4);
157         pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
158
159         err = mlx5_vsc_wait_on_flag(mdev, 0);
160         if (err)
161                 mlx5_core_warn(mdev, "Failed waiting for write flag!\n");
162
163         return err;
164 }
165
166 int mlx5_vsc_read(struct mlx5_core_dev *mdev, u32 addr, u32 *data)
167 {
168         device_t dev = mdev->pdev->dev.bsddev;
169         int vsc_addr = mdev->vsc_addr;
170         int err;
171         u32 in;
172
173         if (!vsc_addr) {
174                 mlx5_core_warn(mdev, "Unable to call vsc read, vsc_addr not initialized\n");
175                 return EINVAL;
176         }
177
178         MLX5_VSC_SET(vsc_addr, &in, address, addr);
179         pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
180
181         err = mlx5_vsc_wait_on_flag(mdev, 1);
182         if (err) {
183                 mlx5_core_warn(mdev, "Failed waiting for read complete flag!\n");
184                 return err;
185         }
186
187         *data = pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4);
188
189         return 0;
190 }
191
192 int mlx5_vsc_find_cap(struct mlx5_core_dev *mdev)
193 {
194         int *capreg = &mdev->vsc_addr;
195         int err;
196
197         err = pci_find_cap(mdev->pdev->dev.bsddev, PCIY_VENDOR, capreg);
198
199         if (err)
200                 *capreg = 0;
201
202         return err;
203 }
204