2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
28 #include <dev/mlx5/driver.h>
29 #include <dev/mlx5/device.h>
30 #include <dev/mlx5/mlx5_core/mlx5_core.h>
32 int mlx5_vsc_lock(struct mlx5_core_dev *mdev)
34 device_t dev = mdev->pdev->dev.bsddev;
35 int vsc_addr = mdev->vsc_addr;
41 mlx5_core_warn(mdev, "Unable to acquire vsc lock, vsc_addr not initialized\n");
46 if (retries > MLX5_VSC_MAX_RETRIES)
49 if (pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4)) {
52 * The PRM suggests random 0 - 10ms to prevent multiple
53 * waiters on the same interval in order to avoid starvation
55 DELAY((random() % 9000) + 1000);
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);
63 if (lock_val == counter)
72 void mlx5_vsc_unlock(struct mlx5_core_dev *mdev)
74 device_t dev = mdev->pdev->dev.bsddev;
75 int vsc_addr = mdev->vsc_addr;
78 mlx5_core_warn(mdev, "Unable to release vsc lock, vsc_addr not initialized\n");
82 pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 0, 4);
86 mlx5_vsc_wait_on_flag(struct mlx5_core_dev *mdev, u32 expected)
88 device_t dev = mdev->pdev->dev.bsddev;
89 int vsc_addr = mdev->vsc_addr;
94 if (retries > MLX5_VSC_MAX_RETRIES)
97 flag = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4);
98 if (expected == MLX5_VSC_GET(vsc_addr, &flag, flag))
102 DELAY((random() % 90) + 10);
108 int mlx5_vsc_set_space(struct mlx5_core_dev *mdev, u16 space)
110 device_t dev = mdev->pdev->dev.bsddev;
111 int vsc_addr = mdev->vsc_addr;
115 mlx5_core_warn(mdev, "Unable to set vsc space, vsc_addr not initialized\n");
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);
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);
131 int mlx5_vsc_write(struct mlx5_core_dev *mdev, u32 addr, const u32 *data)
133 device_t dev = mdev->pdev->dev.bsddev;
134 int vsc_addr = mdev->vsc_addr;
139 mlx5_core_warn(mdev, "Unable to call vsc write, vsc_addr not initialized\n");
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);
148 err = mlx5_vsc_wait_on_flag(mdev, 0);
150 mlx5_core_warn(mdev, "Failed waiting for write flag!\n");
155 int mlx5_vsc_read(struct mlx5_core_dev *mdev, u32 addr, u32 *data)
157 device_t dev = mdev->pdev->dev.bsddev;
158 int vsc_addr = mdev->vsc_addr;
163 mlx5_core_warn(mdev, "Unable to call vsc read, vsc_addr not initialized\n");
167 MLX5_VSC_SET(vsc_addr, &in, address, addr);
168 pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4);
170 err = mlx5_vsc_wait_on_flag(mdev, 1);
172 mlx5_core_warn(mdev, "Failed waiting for read complete flag!\n");
176 *data = pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4);
181 int mlx5_vsc_lock_addr_space(struct mlx5_core_dev *mdev, u32 addr)
183 device_t dev = mdev->pdev->dev.bsddev;
184 int vsc_addr = mdev->vsc_addr;
189 ret = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_SEMAPHORES);
193 /* Get a unique ID based on the counter */
194 id = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4);
196 /* Try to modify lock */
197 ret = mlx5_vsc_write(mdev, addr, &id);
202 ret = mlx5_vsc_read(mdev, addr, &data);
211 int mlx5_vsc_unlock_addr_space(struct mlx5_core_dev *mdev, u32 addr)
216 ret = mlx5_vsc_set_space(mdev, MLX5_VSC_DOMAIN_SEMAPHORES);
220 /* Try to modify lock */
221 ret = mlx5_vsc_write(mdev, addr, &data);
226 ret = mlx5_vsc_read(mdev, addr, &data);
235 int mlx5_vsc_find_cap(struct mlx5_core_dev *mdev)
237 int *capreg = &mdev->vsc_addr;
240 err = pci_find_cap(mdev->pdev->dev.bsddev, PCIY_VENDOR, capreg);