xref: /freebsd/sys/dev/mlx5/mlx5_core/mlx5_vsc.c (revision 4b95c665)
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 
205