14b95c665SHans Petter Selasky /*- 24b95c665SHans Petter Selasky * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved. 34b95c665SHans Petter Selasky * 44b95c665SHans Petter Selasky * Redistribution and use in source and binary forms, with or without 54b95c665SHans Petter Selasky * modification, are permitted provided that the following conditions 64b95c665SHans Petter Selasky * are met: 74b95c665SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright 84b95c665SHans Petter Selasky * notice, this list of conditions and the following disclaimer. 94b95c665SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright 104b95c665SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the 114b95c665SHans Petter Selasky * documentation and/or other materials provided with the distribution. 124b95c665SHans Petter Selasky * 134b95c665SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND 144b95c665SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 154b95c665SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 164b95c665SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 174b95c665SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 184b95c665SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 194b95c665SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 204b95c665SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 214b95c665SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 224b95c665SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 234b95c665SHans Petter Selasky * SUCH DAMAGE. 244b95c665SHans Petter Selasky * 254b95c665SHans Petter Selasky * $FreeBSD$ 264b95c665SHans Petter Selasky */ 274b95c665SHans Petter Selasky 284b95c665SHans Petter Selasky #include <dev/mlx5/driver.h> 294b95c665SHans Petter Selasky #include <dev/mlx5/device.h> 304b95c665SHans Petter Selasky #include <dev/mlx5/mlx5_core/mlx5_core.h> 314b95c665SHans Petter Selasky 32b575d8c8SHans Petter Selasky #define MLX5_SEMAPHORE_SPACE_DOMAIN 0xA 33b575d8c8SHans Petter Selasky 344b95c665SHans Petter Selasky struct mlx5_ifc_vsc_space_bits { 354b95c665SHans Petter Selasky u8 status[0x3]; 364b95c665SHans Petter Selasky u8 reserved0[0xd]; 374b95c665SHans Petter Selasky u8 space[0x10]; 384b95c665SHans Petter Selasky }; 394b95c665SHans Petter Selasky 404b95c665SHans Petter Selasky struct mlx5_ifc_vsc_addr_bits { 414b95c665SHans Petter Selasky u8 flag[0x1]; 424b95c665SHans Petter Selasky u8 reserved0[0x1]; 434b95c665SHans Petter Selasky u8 address[0x1e]; 444b95c665SHans Petter Selasky }; 454b95c665SHans Petter Selasky 464b95c665SHans Petter Selasky int mlx5_vsc_lock(struct mlx5_core_dev *mdev) 474b95c665SHans Petter Selasky { 484b95c665SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 494b95c665SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 504b95c665SHans Petter Selasky int retries = 0; 514b95c665SHans Petter Selasky u32 lock_val; 524b95c665SHans Petter Selasky u32 counter; 534b95c665SHans Petter Selasky 544b95c665SHans Petter Selasky if (!vsc_addr) { 554b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Unable to acquire vsc lock, vsc_addr not initialized\n"); 564b95c665SHans Petter Selasky return EINVAL; 574b95c665SHans Petter Selasky } 584b95c665SHans Petter Selasky 594b95c665SHans Petter Selasky while (true) { 604b95c665SHans Petter Selasky if (retries > MLX5_VSC_MAX_RETRIES) 614b95c665SHans Petter Selasky return EBUSY; 624b95c665SHans Petter Selasky 634b95c665SHans Petter Selasky if (pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4)) { 644b95c665SHans Petter Selasky retries++; 654b95c665SHans Petter Selasky /* 664b95c665SHans Petter Selasky * The PRM suggests random 0 - 10ms to prevent multiple 674b95c665SHans Petter Selasky * waiters on the same interval in order to avoid starvation 684b95c665SHans Petter Selasky */ 694b95c665SHans Petter Selasky DELAY((random() % 11) * 1000); 704b95c665SHans Petter Selasky continue; 714b95c665SHans Petter Selasky } 724b95c665SHans Petter Selasky 734b95c665SHans Petter Selasky counter = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4); 744b95c665SHans Petter Selasky pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, counter, 4); 754b95c665SHans Petter Selasky lock_val = pci_read_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 4); 764b95c665SHans Petter Selasky 774b95c665SHans Petter Selasky if (lock_val == counter) 784b95c665SHans Petter Selasky break; 794b95c665SHans Petter Selasky 804b95c665SHans Petter Selasky retries++; 814b95c665SHans Petter Selasky } 824b95c665SHans Petter Selasky 834b95c665SHans Petter Selasky return 0; 844b95c665SHans Petter Selasky } 854b95c665SHans Petter Selasky 864b95c665SHans Petter Selasky void mlx5_vsc_unlock(struct mlx5_core_dev *mdev) 874b95c665SHans Petter Selasky { 884b95c665SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 894b95c665SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 904b95c665SHans Petter Selasky 914b95c665SHans Petter Selasky if (!vsc_addr) { 924b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Unable to release vsc lock, vsc_addr not initialized\n"); 934b95c665SHans Petter Selasky return; 944b95c665SHans Petter Selasky } 954b95c665SHans Petter Selasky 964b95c665SHans Petter Selasky pci_write_config(dev, vsc_addr + MLX5_VSC_SEMA_OFFSET, 0, 4); 974b95c665SHans Petter Selasky } 984b95c665SHans Petter Selasky 994b95c665SHans Petter Selasky static int mlx5_vsc_wait_on_flag(struct mlx5_core_dev *mdev, u32 expected) 1004b95c665SHans Petter Selasky { 1014b95c665SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 1024b95c665SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 1034b95c665SHans Petter Selasky int retries = 0; 1044b95c665SHans Petter Selasky u32 flag; 1054b95c665SHans Petter Selasky 1064b95c665SHans Petter Selasky while (true) { 1074b95c665SHans Petter Selasky if (retries > MLX5_VSC_MAX_RETRIES) 1084b95c665SHans Petter Selasky return EBUSY; 1094b95c665SHans Petter Selasky 1104b95c665SHans Petter Selasky flag = pci_read_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, 4); 1114b95c665SHans Petter Selasky if (expected == MLX5_VSC_GET(vsc_addr, &flag, flag)) 1124b95c665SHans Petter Selasky break; 1134b95c665SHans Petter Selasky 1144b95c665SHans Petter Selasky retries++; 1154b95c665SHans Petter Selasky DELAY(10); 1164b95c665SHans Petter Selasky } 1174b95c665SHans Petter Selasky 1184b95c665SHans Petter Selasky return 0; 1194b95c665SHans Petter Selasky } 1204b95c665SHans Petter Selasky 1214b95c665SHans Petter Selasky int mlx5_vsc_set_space(struct mlx5_core_dev *mdev, u16 space) 1224b95c665SHans Petter Selasky { 1234b95c665SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 1244b95c665SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 1254b95c665SHans Petter Selasky u32 vsc_space = 0; 1264b95c665SHans Petter Selasky 1274b95c665SHans Petter Selasky if (!vsc_addr) { 1284b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Unable to set vsc space, vsc_addr not initialized\n"); 1294b95c665SHans Petter Selasky return EINVAL; 1304b95c665SHans Petter Selasky } 1314b95c665SHans Petter Selasky 1324b95c665SHans Petter Selasky MLX5_VSC_SET(vsc_space, &vsc_space, space, space); 1334b95c665SHans Petter Selasky pci_write_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, vsc_space, 4); 1344b95c665SHans Petter Selasky vsc_space = pci_read_config(dev, vsc_addr + MLX5_VSC_SPACE_OFFSET, 4); 1354b95c665SHans Petter Selasky 1364b95c665SHans Petter Selasky if (MLX5_VSC_GET(vsc_space, &vsc_space, status) != MLX5_VSC_SPACE_SUPPORTED) { 1374b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Space 0x%x is not supported.\n", space); 1384b95c665SHans Petter Selasky return ENOTSUP; 1394b95c665SHans Petter Selasky } 1404b95c665SHans Petter Selasky 1414b95c665SHans Petter Selasky return 0; 1424b95c665SHans Petter Selasky } 1434b95c665SHans Petter Selasky 144b575d8c8SHans Petter Selasky int mlx5_vsc_write(struct mlx5_core_dev *mdev, u32 addr, const u32 *data) 1454b95c665SHans Petter Selasky { 1464b95c665SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 1474b95c665SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 1484b95c665SHans Petter Selasky u32 in = 0; 1494b95c665SHans Petter Selasky int err; 1504b95c665SHans Petter Selasky 1514b95c665SHans Petter Selasky if (!vsc_addr) { 1524b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Unable to call vsc write, vsc_addr not initialized\n"); 1534b95c665SHans Petter Selasky return EINVAL; 1544b95c665SHans Petter Selasky } 1554b95c665SHans Petter Selasky 1564b95c665SHans Petter Selasky MLX5_VSC_SET(vsc_addr, &in, address, addr); 1574b95c665SHans Petter Selasky MLX5_VSC_SET(vsc_addr, &in, flag, 1); 1584b95c665SHans Petter Selasky pci_write_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, *data, 4); 1594b95c665SHans Petter Selasky pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4); 1604b95c665SHans Petter Selasky 1614b95c665SHans Petter Selasky err = mlx5_vsc_wait_on_flag(mdev, 0); 1624b95c665SHans Petter Selasky if (err) 1634b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Failed waiting for write flag!\n"); 1644b95c665SHans Petter Selasky 1654b95c665SHans Petter Selasky return err; 1664b95c665SHans Petter Selasky } 1674b95c665SHans Petter Selasky 1684b95c665SHans Petter Selasky int mlx5_vsc_read(struct mlx5_core_dev *mdev, u32 addr, u32 *data) 1694b95c665SHans Petter Selasky { 1704b95c665SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 1714b95c665SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 1724b95c665SHans Petter Selasky int err; 1734b95c665SHans Petter Selasky u32 in; 1744b95c665SHans Petter Selasky 1754b95c665SHans Petter Selasky if (!vsc_addr) { 1764b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Unable to call vsc read, vsc_addr not initialized\n"); 1774b95c665SHans Petter Selasky return EINVAL; 1784b95c665SHans Petter Selasky } 1794b95c665SHans Petter Selasky 1804b95c665SHans Petter Selasky MLX5_VSC_SET(vsc_addr, &in, address, addr); 1814b95c665SHans Petter Selasky pci_write_config(dev, vsc_addr + MLX5_VSC_ADDR_OFFSET, in, 4); 1824b95c665SHans Petter Selasky 1834b95c665SHans Petter Selasky err = mlx5_vsc_wait_on_flag(mdev, 1); 1844b95c665SHans Petter Selasky if (err) { 1854b95c665SHans Petter Selasky mlx5_core_warn(mdev, "Failed waiting for read complete flag!\n"); 1864b95c665SHans Petter Selasky return err; 1874b95c665SHans Petter Selasky } 1884b95c665SHans Petter Selasky 1894b95c665SHans Petter Selasky *data = pci_read_config(dev, vsc_addr + MLX5_VSC_DATA_OFFSET, 4); 1904b95c665SHans Petter Selasky 1914b95c665SHans Petter Selasky return 0; 1924b95c665SHans Petter Selasky } 1934b95c665SHans Petter Selasky 194b575d8c8SHans Petter Selasky int mlx5_vsc_lock_addr_space(struct mlx5_core_dev *mdev, u32 addr) 195b575d8c8SHans Petter Selasky { 196b575d8c8SHans Petter Selasky device_t dev = mdev->pdev->dev.bsddev; 197b575d8c8SHans Petter Selasky int vsc_addr = mdev->vsc_addr; 198b575d8c8SHans Petter Selasky u32 data; 199b575d8c8SHans Petter Selasky int ret; 200b575d8c8SHans Petter Selasky u32 id; 201b575d8c8SHans Petter Selasky 202b575d8c8SHans Petter Selasky ret = mlx5_vsc_set_space(mdev, MLX5_SEMAPHORE_SPACE_DOMAIN); 203b575d8c8SHans Petter Selasky if (ret) 204b575d8c8SHans Petter Selasky return ret; 205b575d8c8SHans Petter Selasky 206b575d8c8SHans Petter Selasky /* Get a unique ID based on the counter */ 207b575d8c8SHans Petter Selasky id = pci_read_config(dev, vsc_addr + MLX5_VSC_COUNTER_OFFSET, 4); 208b575d8c8SHans Petter Selasky 209b575d8c8SHans Petter Selasky /* Try to modify lock */ 210b575d8c8SHans Petter Selasky ret = mlx5_vsc_write(mdev, addr, &id); 211b575d8c8SHans Petter Selasky if (ret) 212b575d8c8SHans Petter Selasky return ret; 213b575d8c8SHans Petter Selasky 214b575d8c8SHans Petter Selasky /* Verify */ 215b575d8c8SHans Petter Selasky ret = mlx5_vsc_read(mdev, addr, &data); 216b575d8c8SHans Petter Selasky if (ret) 217b575d8c8SHans Petter Selasky return ret; 218b575d8c8SHans Petter Selasky if (data != id) 219b575d8c8SHans Petter Selasky return EBUSY; 220b575d8c8SHans Petter Selasky 221b575d8c8SHans Petter Selasky return 0; 222b575d8c8SHans Petter Selasky } 223b575d8c8SHans Petter Selasky 224b575d8c8SHans Petter Selasky int mlx5_vsc_unlock_addr_space(struct mlx5_core_dev *mdev, u32 addr) 225b575d8c8SHans Petter Selasky { 226b575d8c8SHans Petter Selasky u32 data = 0; 227b575d8c8SHans Petter Selasky int ret; 228b575d8c8SHans Petter Selasky 229b575d8c8SHans Petter Selasky ret = mlx5_vsc_set_space(mdev, MLX5_SEMAPHORE_SPACE_DOMAIN); 230b575d8c8SHans Petter Selasky if (ret) 231b575d8c8SHans Petter Selasky return ret; 232b575d8c8SHans Petter Selasky 233b575d8c8SHans Petter Selasky /* Try to modify lock */ 234b575d8c8SHans Petter Selasky ret = mlx5_vsc_write(mdev, addr, &data); 235b575d8c8SHans Petter Selasky if (ret) 236b575d8c8SHans Petter Selasky return ret; 237b575d8c8SHans Petter Selasky 238b575d8c8SHans Petter Selasky /* Verify */ 239b575d8c8SHans Petter Selasky ret = mlx5_vsc_read(mdev, addr, &data); 240b575d8c8SHans Petter Selasky if (ret) 241b575d8c8SHans Petter Selasky return ret; 242b575d8c8SHans Petter Selasky if (data != 0) 243b575d8c8SHans Petter Selasky return EBUSY; 244b575d8c8SHans Petter Selasky 245b575d8c8SHans Petter Selasky return 0; 246b575d8c8SHans Petter Selasky } 247b575d8c8SHans Petter Selasky 2484b95c665SHans Petter Selasky int mlx5_vsc_find_cap(struct mlx5_core_dev *mdev) 2494b95c665SHans Petter Selasky { 2504b95c665SHans Petter Selasky int *capreg = &mdev->vsc_addr; 2514b95c665SHans Petter Selasky int err; 2524b95c665SHans Petter Selasky 2534b95c665SHans Petter Selasky err = pci_find_cap(mdev->pdev->dev.bsddev, PCIY_VENDOR, capreg); 2544b95c665SHans Petter Selasky 2554b95c665SHans Petter Selasky if (err) 2564b95c665SHans Petter Selasky *capreg = 0; 2574b95c665SHans Petter Selasky 2584b95c665SHans Petter Selasky return err; 2594b95c665SHans Petter Selasky } 2604b95c665SHans Petter Selasky 261