sense.c revision 219820
1219820Sjeff/* 2219820Sjeff * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#include <linux/errno.h> 35219820Sjeff#include <linux/if_ether.h> 36219820Sjeff 37219820Sjeff#include <linux/mlx4/cmd.h> 38219820Sjeff 39219820Sjeff#include "mlx4.h" 40219820Sjeff 41219820Sjeffstatic int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, 42219820Sjeff enum mlx4_port_type *type) 43219820Sjeff{ 44219820Sjeff u64 out_param; 45219820Sjeff int err = 0; 46219820Sjeff 47219820Sjeff err = mlx4_cmd_imm(dev, 0, &out_param, port, 0, 48219820Sjeff MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B); 49219820Sjeff if (err) { 50219820Sjeff mlx4_err(dev, "Sense command failed for port: %d\n", port); 51219820Sjeff return err; 52219820Sjeff } 53219820Sjeff 54219820Sjeff if (out_param > 2) { 55219820Sjeff mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", out_param); 56219820Sjeff return EINVAL; 57219820Sjeff } 58219820Sjeff 59219820Sjeff *type = out_param; 60219820Sjeff return 0; 61219820Sjeff} 62219820Sjeff 63219820Sjeffvoid mlx4_do_sense_ports(struct mlx4_dev *dev, 64219820Sjeff enum mlx4_port_type *stype, 65219820Sjeff enum mlx4_port_type *defaults) 66219820Sjeff{ 67219820Sjeff struct mlx4_sense *sense = &mlx4_priv(dev)->sense; 68219820Sjeff int err; 69219820Sjeff int i; 70219820Sjeff 71219820Sjeff for (i = 1; i <= dev->caps.num_ports; i++) { 72219820Sjeff stype[i - 1] = 0; 73219820Sjeff if (sense->do_sense_port[i] && sense->sense_allowed[i] && 74219820Sjeff dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) { 75219820Sjeff err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]); 76219820Sjeff if (err) 77219820Sjeff stype[i - 1] = defaults[i - 1]; 78219820Sjeff } else 79219820Sjeff stype[i - 1] = defaults[i - 1]; 80219820Sjeff } 81219820Sjeff 82219820Sjeff /* 83219820Sjeff * Adjust port configuration: 84219820Sjeff * If port 1 sensed nothing and port 2 is IB, set both as IB 85219820Sjeff * If port 2 sensed nothing and port 1 is Eth, set both as Eth 86219820Sjeff */ 87219820Sjeff if (stype[0] == MLX4_PORT_TYPE_ETH) { 88219820Sjeff for (i = 1; i < dev->caps.num_ports; i++) 89219820Sjeff stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH; 90219820Sjeff } 91219820Sjeff if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) { 92219820Sjeff for (i = 0; i < dev->caps.num_ports - 1; i++) 93219820Sjeff stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB; 94219820Sjeff } 95219820Sjeff 96219820Sjeff /* 97219820Sjeff * If sensed nothing, remain in current configuration. 98219820Sjeff */ 99219820Sjeff for (i = 0; i < dev->caps.num_ports; i++) 100219820Sjeff stype[i] = stype[i] ? stype[i] : defaults[i]; 101219820Sjeff 102219820Sjeff} 103219820Sjeff 104219820Sjeffstatic void mlx4_sense_port(struct work_struct *work) 105219820Sjeff{ 106219820Sjeff struct delayed_work *delay = to_delayed_work(work); 107219820Sjeff struct mlx4_sense *sense = container_of(delay, struct mlx4_sense, 108219820Sjeff sense_poll); 109219820Sjeff struct mlx4_dev *dev = sense->dev; 110219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 111219820Sjeff enum mlx4_port_type stype[MLX4_MAX_PORTS]; 112219820Sjeff 113219820Sjeff mutex_lock(&priv->port_mutex); 114219820Sjeff mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]); 115219820Sjeff 116219820Sjeff if (mlx4_check_port_params(dev, stype)) 117219820Sjeff goto sense_again; 118219820Sjeff 119219820Sjeff if (mlx4_change_port_types(dev, stype)) 120219820Sjeff mlx4_err(dev, "Failed to change port_types\n"); 121219820Sjeff 122219820Sjeffsense_again: 123219820Sjeff mutex_unlock(&priv->port_mutex); 124219820Sjeff if (sense->resched) 125219820Sjeff queue_delayed_work(sense->sense_wq , &sense->sense_poll, 126219820Sjeff round_jiffies(MLX4_SENSE_RANGE)); 127219820Sjeff} 128219820Sjeff 129219820Sjeffvoid mlx4_start_sense(struct mlx4_dev *dev) 130219820Sjeff{ 131219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 132219820Sjeff struct mlx4_sense *sense = &priv->sense; 133219820Sjeff 134219820Sjeff if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) 135219820Sjeff return; 136219820Sjeff 137219820Sjeff sense->resched = 1; 138219820Sjeff queue_delayed_work(sense->sense_wq , &sense->sense_poll, 139219820Sjeff round_jiffies(MLX4_SENSE_RANGE)); 140219820Sjeff} 141219820Sjeff 142219820Sjeff 143219820Sjeffvoid mlx4_stop_sense(struct mlx4_dev *dev) 144219820Sjeff{ 145219820Sjeff mlx4_priv(dev)->sense.resched = 0; 146219820Sjeff} 147219820Sjeff 148219820Sjeffint mlx4_sense_init(struct mlx4_dev *dev) 149219820Sjeff{ 150219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 151219820Sjeff struct mlx4_sense *sense = &priv->sense; 152219820Sjeff int port; 153219820Sjeff 154219820Sjeff sense->dev = dev; 155219820Sjeff sense->sense_wq = create_singlethread_workqueue("mlx4_sense"); 156219820Sjeff if (!sense->sense_wq) 157219820Sjeff return -ENOMEM; 158219820Sjeff 159219820Sjeff for (port = 1; port <= dev->caps.num_ports; port++) 160219820Sjeff sense->do_sense_port[port] = 1; 161219820Sjeff 162219820Sjeff INIT_DELAYED_WORK_DEFERRABLE(&sense->sense_poll, mlx4_sense_port); 163219820Sjeff return 0; 164219820Sjeff} 165219820Sjeff 166219820Sjeffvoid mlx4_sense_cleanup(struct mlx4_dev *dev) 167219820Sjeff{ 168219820Sjeff mlx4_stop_sense(dev); 169219820Sjeff cancel_delayed_work(&mlx4_priv(dev)->sense.sense_poll); 170219820Sjeff destroy_workqueue(mlx4_priv(dev)->sense.sense_wq); 171219820Sjeff} 172219820Sjeff 173