162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/errno.h> 3562306a36Sopenharmony_ci#include <linux/if_ether.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <linux/mlx4/cmd.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include "mlx4.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciint mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, 4262306a36Sopenharmony_ci enum mlx4_port_type *type) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci u64 out_param; 4562306a36Sopenharmony_ci int err = 0; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci err = mlx4_cmd_imm(dev, 0, &out_param, port, 0, 4862306a36Sopenharmony_ci MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B, 4962306a36Sopenharmony_ci MLX4_CMD_WRAPPED); 5062306a36Sopenharmony_ci if (err) { 5162306a36Sopenharmony_ci mlx4_err(dev, "Sense command failed for port: %d\n", port); 5262306a36Sopenharmony_ci return err; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (out_param > 2) { 5662306a36Sopenharmony_ci mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", out_param); 5762306a36Sopenharmony_ci return -EINVAL; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci *type = out_param; 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_civoid mlx4_do_sense_ports(struct mlx4_dev *dev, 6562306a36Sopenharmony_ci enum mlx4_port_type *stype, 6662306a36Sopenharmony_ci enum mlx4_port_type *defaults) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct mlx4_sense *sense = &mlx4_priv(dev)->sense; 6962306a36Sopenharmony_ci int err; 7062306a36Sopenharmony_ci int i; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (i = 1; i <= dev->caps.num_ports; i++) { 7362306a36Sopenharmony_ci stype[i - 1] = 0; 7462306a36Sopenharmony_ci if (sense->do_sense_port[i] && sense->sense_allowed[i] && 7562306a36Sopenharmony_ci dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { 7662306a36Sopenharmony_ci err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]); 7762306a36Sopenharmony_ci if (err) 7862306a36Sopenharmony_ci stype[i - 1] = defaults[i - 1]; 7962306a36Sopenharmony_ci } else 8062306a36Sopenharmony_ci stype[i - 1] = defaults[i - 1]; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * If sensed nothing, remain in current configuration. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci for (i = 0; i < dev->caps.num_ports; i++) 8762306a36Sopenharmony_ci stype[i] = stype[i] ? stype[i] : defaults[i]; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void mlx4_sense_port(struct work_struct *work) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct delayed_work *delay = to_delayed_work(work); 9462306a36Sopenharmony_ci struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, 9562306a36Sopenharmony_ci sense_poll); 9662306a36Sopenharmony_ci struct mlx4_dev *dev = sense->dev; 9762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 9862306a36Sopenharmony_ci enum mlx4_port_type stype[MLX4_MAX_PORTS]; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci mutex_lock(&priv->port_mutex); 10162306a36Sopenharmony_ci mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (mlx4_check_port_params(dev, stype)) 10462306a36Sopenharmony_ci goto sense_again; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (mlx4_change_port_types(dev, stype)) 10762306a36Sopenharmony_ci mlx4_err(dev, "Failed to change port_types\n"); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cisense_again: 11062306a36Sopenharmony_ci mutex_unlock(&priv->port_mutex); 11162306a36Sopenharmony_ci queue_delayed_work(mlx4_wq , &sense->sense_poll, 11262306a36Sopenharmony_ci round_jiffies_relative(MLX4_SENSE_RANGE)); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_civoid mlx4_start_sense(struct mlx4_dev *dev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 11862306a36Sopenharmony_ci struct mlx4_sense *sense = &priv->sense; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) 12162306a36Sopenharmony_ci return; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci queue_delayed_work(mlx4_wq , &sense->sense_poll, 12462306a36Sopenharmony_ci round_jiffies_relative(MLX4_SENSE_RANGE)); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid mlx4_stop_sense(struct mlx4_dev *dev) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci cancel_delayed_work_sync(&mlx4_priv(dev)->sense.sense_poll); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_civoid mlx4_sense_init(struct mlx4_dev *dev) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct mlx4_priv *priv = mlx4_priv(dev); 13562306a36Sopenharmony_ci struct mlx4_sense *sense = &priv->sense; 13662306a36Sopenharmony_ci int port; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci sense->dev = dev; 13962306a36Sopenharmony_ci for (port = 1; port <= dev->caps.num_ports; port++) 14062306a36Sopenharmony_ci sense->do_sense_port[port] = 1; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci INIT_DEFERRABLE_WORK(&sense->sense_poll, mlx4_sense_port); 14362306a36Sopenharmony_ci} 144