18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/errno.h> 358c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "mlx4.h" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciint mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, 428c2ecf20Sopenharmony_ci enum mlx4_port_type *type) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci u64 out_param; 458c2ecf20Sopenharmony_ci int err = 0; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci err = mlx4_cmd_imm(dev, 0, &out_param, port, 0, 488c2ecf20Sopenharmony_ci MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B, 498c2ecf20Sopenharmony_ci MLX4_CMD_WRAPPED); 508c2ecf20Sopenharmony_ci if (err) { 518c2ecf20Sopenharmony_ci mlx4_err(dev, "Sense command failed for port: %d\n", port); 528c2ecf20Sopenharmony_ci return err; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (out_param > 2) { 568c2ecf20Sopenharmony_ci mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", out_param); 578c2ecf20Sopenharmony_ci return -EINVAL; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci *type = out_param; 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_civoid mlx4_do_sense_ports(struct mlx4_dev *dev, 658c2ecf20Sopenharmony_ci enum mlx4_port_type *stype, 668c2ecf20Sopenharmony_ci enum mlx4_port_type *defaults) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct mlx4_sense *sense = &mlx4_priv(dev)->sense; 698c2ecf20Sopenharmony_ci int err; 708c2ecf20Sopenharmony_ci int i; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci for (i = 1; i <= dev->caps.num_ports; i++) { 738c2ecf20Sopenharmony_ci stype[i - 1] = 0; 748c2ecf20Sopenharmony_ci if (sense->do_sense_port[i] && sense->sense_allowed[i] && 758c2ecf20Sopenharmony_ci dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { 768c2ecf20Sopenharmony_ci err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]); 778c2ecf20Sopenharmony_ci if (err) 788c2ecf20Sopenharmony_ci stype[i - 1] = defaults[i - 1]; 798c2ecf20Sopenharmony_ci } else 808c2ecf20Sopenharmony_ci stype[i - 1] = defaults[i - 1]; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* 848c2ecf20Sopenharmony_ci * If sensed nothing, remain in current configuration. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci for (i = 0; i < dev->caps.num_ports; i++) 878c2ecf20Sopenharmony_ci stype[i] = stype[i] ? stype[i] : defaults[i]; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void mlx4_sense_port(struct work_struct *work) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 948c2ecf20Sopenharmony_ci struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, 958c2ecf20Sopenharmony_ci sense_poll); 968c2ecf20Sopenharmony_ci struct mlx4_dev *dev = sense->dev; 978c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 988c2ecf20Sopenharmony_ci enum mlx4_port_type stype[MLX4_MAX_PORTS]; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci mutex_lock(&priv->port_mutex); 1018c2ecf20Sopenharmony_ci mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci if (mlx4_check_port_params(dev, stype)) 1048c2ecf20Sopenharmony_ci goto sense_again; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (mlx4_change_port_types(dev, stype)) 1078c2ecf20Sopenharmony_ci mlx4_err(dev, "Failed to change port_types\n"); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cisense_again: 1108c2ecf20Sopenharmony_ci mutex_unlock(&priv->port_mutex); 1118c2ecf20Sopenharmony_ci queue_delayed_work(mlx4_wq , &sense->sense_poll, 1128c2ecf20Sopenharmony_ci round_jiffies_relative(MLX4_SENSE_RANGE)); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid mlx4_start_sense(struct mlx4_dev *dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 1188c2ecf20Sopenharmony_ci struct mlx4_sense *sense = &priv->sense; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) 1218c2ecf20Sopenharmony_ci return; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci queue_delayed_work(mlx4_wq , &sense->sense_poll, 1248c2ecf20Sopenharmony_ci round_jiffies_relative(MLX4_SENSE_RANGE)); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_civoid mlx4_stop_sense(struct mlx4_dev *dev) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&mlx4_priv(dev)->sense.sense_poll); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_civoid mlx4_sense_init(struct mlx4_dev *dev) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 1358c2ecf20Sopenharmony_ci struct mlx4_sense *sense = &priv->sense; 1368c2ecf20Sopenharmony_ci int port; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci sense->dev = dev; 1398c2ecf20Sopenharmony_ci for (port = 1; port <= dev->caps.num_ports; port++) 1408c2ecf20Sopenharmony_ci sense->do_sense_port[port] = 1; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci INIT_DEFERRABLE_WORK(&sense->sense_poll, mlx4_sense_port); 1438c2ecf20Sopenharmony_ci} 144