aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorYevgeny Petrilin <yevgenyp@mellanox.co.il>2009-03-18 22:45:11 -0400
committerRoland Dreier <rolandd@cisco.com>2009-03-18 22:45:11 -0400
commit27bf91d6a0d5a9c7224e8687754249bba67dd4cf (patch)
tree55c253fa4438ea29d73f072a88dff5fb74e2ca4e /drivers/net
parent793730bfb6711d6d14629e63845c25a3c14d205e (diff)
mlx4_core: Add link type autosensing
When a port's link is down (except to driver restart) and the port is configured for auto sensing, we try to sense port link type (Ethernet or InfiniBand) in order to determine how to initialize the port. If the port type needs to be changed, all mlx4 for the device interfaces are unregistered and then registered again with the new port types. Sensing is done with intervals of 3 seconds. Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/mlx4/Makefile2
-rw-r--r--drivers/net/mlx4/catas.c16
-rw-r--r--drivers/net/mlx4/eq.c16
-rw-r--r--drivers/net/mlx4/main.c104
-rw-r--r--drivers/net/mlx4/mlx4.h27
-rw-r--r--drivers/net/mlx4/sense.c156
6 files changed, 272 insertions, 49 deletions
diff --git a/drivers/net/mlx4/Makefile b/drivers/net/mlx4/Makefile
index a7a97bf998f8..21040a0d81fe 100644
--- a/drivers/net/mlx4/Makefile
+++ b/drivers/net/mlx4/Makefile
@@ -1,7 +1,7 @@
1obj-$(CONFIG_MLX4_CORE) += mlx4_core.o 1obj-$(CONFIG_MLX4_CORE) += mlx4_core.o
2 2
3mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ 3mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
4 mr.o pd.o port.o profile.o qp.o reset.o srq.o 4 mr.o pd.o port.o profile.o qp.o reset.o sense.o srq.o
5 5
6obj-$(CONFIG_MLX4_EN) += mlx4_en.o 6obj-$(CONFIG_MLX4_EN) += mlx4_en.o
7 7
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index f094ee00c416..aa9674b7f19c 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -42,7 +42,6 @@ enum {
42static DEFINE_SPINLOCK(catas_lock); 42static DEFINE_SPINLOCK(catas_lock);
43 43
44static LIST_HEAD(catas_list); 44static LIST_HEAD(catas_list);
45static struct workqueue_struct *catas_wq;
46static struct work_struct catas_work; 45static struct work_struct catas_work;
47 46
48static int internal_err_reset = 1; 47static int internal_err_reset = 1;
@@ -77,7 +76,7 @@ static void poll_catas(unsigned long dev_ptr)
77 list_add(&priv->catas_err.list, &catas_list); 76 list_add(&priv->catas_err.list, &catas_list);
78 spin_unlock(&catas_lock); 77 spin_unlock(&catas_lock);
79 78
80 queue_work(catas_wq, &catas_work); 79 queue_work(mlx4_wq, &catas_work);
81 } 80 }
82 } else 81 } else
83 mod_timer(&priv->catas_err.timer, 82 mod_timer(&priv->catas_err.timer,
@@ -146,18 +145,7 @@ void mlx4_stop_catas_poll(struct mlx4_dev *dev)
146 spin_unlock_irq(&catas_lock); 145 spin_unlock_irq(&catas_lock);
147} 146}
148 147
149int __init mlx4_catas_init(void) 148void __init mlx4_catas_init(void)
150{ 149{
151 INIT_WORK(&catas_work, catas_reset); 150 INIT_WORK(&catas_work, catas_reset);
152
153 catas_wq = create_singlethread_workqueue("mlx4_err");
154 if (!catas_wq)
155 return -ENOMEM;
156
157 return 0;
158}
159
160void mlx4_catas_cleanup(void)
161{
162 destroy_workqueue(catas_wq);
163} 151}
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 2c19bff7cbab..8830dcb92ec8 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -163,6 +163,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
163 int cqn; 163 int cqn;
164 int eqes_found = 0; 164 int eqes_found = 0;
165 int set_ci = 0; 165 int set_ci = 0;
166 int port;
166 167
167 while ((eqe = next_eqe_sw(eq))) { 168 while ((eqe = next_eqe_sw(eq))) {
168 /* 169 /*
@@ -203,11 +204,16 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
203 break; 204 break;
204 205
205 case MLX4_EVENT_TYPE_PORT_CHANGE: 206 case MLX4_EVENT_TYPE_PORT_CHANGE:
206 mlx4_dispatch_event(dev, 207 port = be32_to_cpu(eqe->event.port_change.port) >> 28;
207 eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_ACTIVE ? 208 if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) {
208 MLX4_DEV_EVENT_PORT_UP : 209 mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN,
209 MLX4_DEV_EVENT_PORT_DOWN, 210 port);
210 be32_to_cpu(eqe->event.port_change.port) >> 28); 211 mlx4_priv(dev)->sense.do_sense_port[port] = 1;
212 } else {
213 mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP,
214 port);
215 mlx4_priv(dev)->sense.do_sense_port[port] = 0;
216 }
211 break; 217 break;
212 218
213 case MLX4_EVENT_TYPE_CQ_ERROR: 219 case MLX4_EVENT_TYPE_CQ_ERROR:
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 8480f0346844..a66f5b2fd288 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -51,6 +51,8 @@ MODULE_DESCRIPTION("Mellanox ConnectX HCA low-level driver");
51MODULE_LICENSE("Dual BSD/GPL"); 51MODULE_LICENSE("Dual BSD/GPL");
52MODULE_VERSION(DRV_VERSION); 52MODULE_VERSION(DRV_VERSION);
53 53
54struct workqueue_struct *mlx4_wq;
55
54#ifdef CONFIG_MLX4_DEBUG 56#ifdef CONFIG_MLX4_DEBUG
55 57
56int mlx4_debug_level = 0; 58int mlx4_debug_level = 0;
@@ -98,24 +100,23 @@ module_param_named(use_prio, use_prio, bool, 0444);
98MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports " 100MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
99 "(0/1, default 0)"); 101 "(0/1, default 0)");
100 102
101static int mlx4_check_port_params(struct mlx4_dev *dev, 103int mlx4_check_port_params(struct mlx4_dev *dev,
102 enum mlx4_port_type *port_type) 104 enum mlx4_port_type *port_type)
103{ 105{
104 int i; 106 int i;
105 107
106 for (i = 0; i < dev->caps.num_ports - 1; i++) { 108 for (i = 0; i < dev->caps.num_ports - 1; i++) {
107 if (port_type[i] != port_type[i+1] && 109 if (port_type[i] != port_type[i + 1]) {
108 !(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) { 110 if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) {
109 mlx4_err(dev, "Only same port types supported " 111 mlx4_err(dev, "Only same port types supported "
110 "on this HCA, aborting.\n"); 112 "on this HCA, aborting.\n");
111 return -EINVAL; 113 return -EINVAL;
114 }
115 if (port_type[i] == MLX4_PORT_TYPE_ETH &&
116 port_type[i + 1] == MLX4_PORT_TYPE_IB)
117 return -EINVAL;
112 } 118 }
113 } 119 }
114 if ((port_type[0] == MLX4_PORT_TYPE_ETH) &&
115 (port_type[1] == MLX4_PORT_TYPE_IB)) {
116 mlx4_err(dev, "eth-ib configuration is not supported.\n");
117 return -EINVAL;
118 }
119 120
120 for (i = 0; i < dev->caps.num_ports; i++) { 121 for (i = 0; i < dev->caps.num_ports; i++) {
121 if (!(port_type[i] & dev->caps.supported_type[i+1])) { 122 if (!(port_type[i] & dev->caps.supported_type[i+1])) {
@@ -225,6 +226,9 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
225 dev->caps.port_type[i] = MLX4_PORT_TYPE_IB; 226 dev->caps.port_type[i] = MLX4_PORT_TYPE_IB;
226 else 227 else
227 dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH; 228 dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH;
229 dev->caps.possible_type[i] = dev->caps.port_type[i];
230 mlx4_priv(dev)->sense.sense_allowed[i] =
231 dev->caps.supported_type[i] == MLX4_PORT_TYPE_AUTO;
228 232
229 if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) { 233 if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) {
230 dev->caps.log_num_macs = dev_cap->log_max_macs[i]; 234 dev->caps.log_num_macs = dev_cap->log_max_macs[i];
@@ -263,14 +267,16 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
263 * Change the port configuration of the device. 267 * Change the port configuration of the device.
264 * Every user of this function must hold the port mutex. 268 * Every user of this function must hold the port mutex.
265 */ 269 */
266static int mlx4_change_port_types(struct mlx4_dev *dev, 270int mlx4_change_port_types(struct mlx4_dev *dev,
267 enum mlx4_port_type *port_types) 271 enum mlx4_port_type *port_types)
268{ 272{
269 int err = 0; 273 int err = 0;
270 int change = 0; 274 int change = 0;
271 int port; 275 int port;
272 276
273 for (port = 0; port < dev->caps.num_ports; port++) { 277 for (port = 0; port < dev->caps.num_ports; port++) {
278 /* Change the port type only if the new type is different
279 * from the current, and not set to Auto */
274 if (port_types[port] != dev->caps.port_type[port + 1]) { 280 if (port_types[port] != dev->caps.port_type[port + 1]) {
275 change = 1; 281 change = 1;
276 dev->caps.port_type[port + 1] = port_types[port]; 282 dev->caps.port_type[port + 1] = port_types[port];
@@ -302,10 +308,17 @@ static ssize_t show_port_type(struct device *dev,
302 struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info, 308 struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
303 port_attr); 309 port_attr);
304 struct mlx4_dev *mdev = info->dev; 310 struct mlx4_dev *mdev = info->dev;
311 char type[8];
312
313 sprintf(type, "%s",
314 (mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB) ?
315 "ib" : "eth");
316 if (mdev->caps.possible_type[info->port] == MLX4_PORT_TYPE_AUTO)
317 sprintf(buf, "auto (%s)\n", type);
318 else
319 sprintf(buf, "%s\n", type);
305 320
306 return sprintf(buf, "%s\n", 321 return strlen(buf);
307 mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB ?
308 "ib" : "eth");
309} 322}
310 323
311static ssize_t set_port_type(struct device *dev, 324static ssize_t set_port_type(struct device *dev,
@@ -317,6 +330,7 @@ static ssize_t set_port_type(struct device *dev,
317 struct mlx4_dev *mdev = info->dev; 330 struct mlx4_dev *mdev = info->dev;
318 struct mlx4_priv *priv = mlx4_priv(mdev); 331 struct mlx4_priv *priv = mlx4_priv(mdev);
319 enum mlx4_port_type types[MLX4_MAX_PORTS]; 332 enum mlx4_port_type types[MLX4_MAX_PORTS];
333 enum mlx4_port_type new_types[MLX4_MAX_PORTS];
320 int i; 334 int i;
321 int err = 0; 335 int err = 0;
322 336
@@ -324,26 +338,56 @@ static ssize_t set_port_type(struct device *dev,
324 info->tmp_type = MLX4_PORT_TYPE_IB; 338 info->tmp_type = MLX4_PORT_TYPE_IB;
325 else if (!strcmp(buf, "eth\n")) 339 else if (!strcmp(buf, "eth\n"))
326 info->tmp_type = MLX4_PORT_TYPE_ETH; 340 info->tmp_type = MLX4_PORT_TYPE_ETH;
341 else if (!strcmp(buf, "auto\n"))
342 info->tmp_type = MLX4_PORT_TYPE_AUTO;
327 else { 343 else {
328 mlx4_err(mdev, "%s is not supported port type\n", buf); 344 mlx4_err(mdev, "%s is not supported port type\n", buf);
329 return -EINVAL; 345 return -EINVAL;
330 } 346 }
331 347
348 mlx4_stop_sense(mdev);
332 mutex_lock(&priv->port_mutex); 349 mutex_lock(&priv->port_mutex);
333 for (i = 0; i < mdev->caps.num_ports; i++) 350 /* Possible type is always the one that was delivered */
351 mdev->caps.possible_type[info->port] = info->tmp_type;
352
353 for (i = 0; i < mdev->caps.num_ports; i++) {
334 types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type : 354 types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type :
335 mdev->caps.port_type[i+1]; 355 mdev->caps.possible_type[i+1];
356 if (types[i] == MLX4_PORT_TYPE_AUTO)
357 types[i] = mdev->caps.port_type[i+1];
358 }
336 359
337 err = mlx4_check_port_params(mdev, types); 360 if (!(mdev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) {
361 for (i = 1; i <= mdev->caps.num_ports; i++) {
362 if (mdev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) {
363 mdev->caps.possible_type[i] = mdev->caps.port_type[i];
364 err = -EINVAL;
365 }
366 }
367 }
368 if (err) {
369 mlx4_err(mdev, "Auto sensing is not supported on this HCA. "
370 "Set only 'eth' or 'ib' for both ports "
371 "(should be the same)\n");
372 goto out;
373 }
374
375 mlx4_do_sense_ports(mdev, new_types, types);
376
377 err = mlx4_check_port_params(mdev, new_types);
338 if (err) 378 if (err)
339 goto out; 379 goto out;
340 380
341 for (i = 1; i <= mdev->caps.num_ports; i++) 381 /* We are about to apply the changes after the configuration
342 priv->port[i].tmp_type = 0; 382 * was verified, no need to remember the temporary types
383 * any more */
384 for (i = 0; i < mdev->caps.num_ports; i++)
385 priv->port[i + 1].tmp_type = 0;
343 386
344 err = mlx4_change_port_types(mdev, types); 387 err = mlx4_change_port_types(mdev, new_types);
345 388
346out: 389out:
390 mlx4_start_sense(mdev);
347 mutex_unlock(&priv->port_mutex); 391 mutex_unlock(&priv->port_mutex);
348 return err ? err : count; 392 return err ? err : count;
349} 393}
@@ -1117,6 +1161,9 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
1117 if (err) 1161 if (err)
1118 goto err_port; 1162 goto err_port;
1119 1163
1164 mlx4_sense_init(dev);
1165 mlx4_start_sense(dev);
1166
1120 pci_set_drvdata(pdev, dev); 1167 pci_set_drvdata(pdev, dev);
1121 1168
1122 return 0; 1169 return 0;
@@ -1182,6 +1229,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
1182 int p; 1229 int p;
1183 1230
1184 if (dev) { 1231 if (dev) {
1232 mlx4_stop_sense(dev);
1185 mlx4_unregister_device(dev); 1233 mlx4_unregister_device(dev);
1186 1234
1187 for (p = 1; p <= dev->caps.num_ports; p++) { 1235 for (p = 1; p <= dev->caps.num_ports; p++) {
@@ -1266,9 +1314,11 @@ static int __init mlx4_init(void)
1266 if (mlx4_verify_params()) 1314 if (mlx4_verify_params())
1267 return -EINVAL; 1315 return -EINVAL;
1268 1316
1269 ret = mlx4_catas_init(); 1317 mlx4_catas_init();
1270 if (ret) 1318
1271 return ret; 1319 mlx4_wq = create_singlethread_workqueue("mlx4");
1320 if (!mlx4_wq)
1321 return -ENOMEM;
1272 1322
1273 ret = pci_register_driver(&mlx4_driver); 1323 ret = pci_register_driver(&mlx4_driver);
1274 return ret < 0 ? ret : 0; 1324 return ret < 0 ? ret : 0;
@@ -1277,7 +1327,7 @@ static int __init mlx4_init(void)
1277static void __exit mlx4_cleanup(void) 1327static void __exit mlx4_cleanup(void)
1278{ 1328{
1279 pci_unregister_driver(&mlx4_driver); 1329 pci_unregister_driver(&mlx4_driver);
1280 mlx4_catas_cleanup(); 1330 destroy_workqueue(mlx4_wq);
1281} 1331}
1282 1332
1283module_init(mlx4_init); 1333module_init(mlx4_init);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index e0213bad61c7..5bd79c2b184f 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -40,6 +40,7 @@
40#include <linux/mutex.h> 40#include <linux/mutex.h>
41#include <linux/radix-tree.h> 41#include <linux/radix-tree.h>
42#include <linux/timer.h> 42#include <linux/timer.h>
43#include <linux/workqueue.h>
43 44
44#include <linux/mlx4/device.h> 45#include <linux/mlx4/device.h>
45#include <linux/mlx4/driver.h> 46#include <linux/mlx4/driver.h>
@@ -276,6 +277,13 @@ struct mlx4_port_info {
276 struct mlx4_vlan_table vlan_table; 277 struct mlx4_vlan_table vlan_table;
277}; 278};
278 279
280struct mlx4_sense {
281 struct mlx4_dev *dev;
282 u8 do_sense_port[MLX4_MAX_PORTS + 1];
283 u8 sense_allowed[MLX4_MAX_PORTS + 1];
284 struct delayed_work sense_poll;
285};
286
279struct mlx4_priv { 287struct mlx4_priv {
280 struct mlx4_dev dev; 288 struct mlx4_dev dev;
281 289
@@ -305,6 +313,7 @@ struct mlx4_priv {
305 struct mlx4_uar driver_uar; 313 struct mlx4_uar driver_uar;
306 void __iomem *kar; 314 void __iomem *kar;
307 struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; 315 struct mlx4_port_info port[MLX4_MAX_PORTS + 1];
316 struct mlx4_sense sense;
308 struct mutex port_mutex; 317 struct mutex port_mutex;
309}; 318};
310 319
@@ -313,6 +322,10 @@ static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
313 return container_of(dev, struct mlx4_priv, dev); 322 return container_of(dev, struct mlx4_priv, dev);
314} 323}
315 324
325#define MLX4_SENSE_RANGE (HZ * 3)
326
327extern struct workqueue_struct *mlx4_wq;
328
316u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); 329u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap);
317void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); 330void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj);
318u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); 331u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align);
@@ -346,8 +359,7 @@ void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
346 359
347void mlx4_start_catas_poll(struct mlx4_dev *dev); 360void mlx4_start_catas_poll(struct mlx4_dev *dev);
348void mlx4_stop_catas_poll(struct mlx4_dev *dev); 361void mlx4_stop_catas_poll(struct mlx4_dev *dev);
349int mlx4_catas_init(void); 362void mlx4_catas_init(void);
350void mlx4_catas_cleanup(void);
351int mlx4_restart_one(struct pci_dev *pdev); 363int mlx4_restart_one(struct pci_dev *pdev);
352int mlx4_register_device(struct mlx4_dev *dev); 364int mlx4_register_device(struct mlx4_dev *dev);
353void mlx4_unregister_device(struct mlx4_dev *dev); 365void mlx4_unregister_device(struct mlx4_dev *dev);
@@ -379,6 +391,17 @@ void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
379 391
380void mlx4_handle_catas_err(struct mlx4_dev *dev); 392void mlx4_handle_catas_err(struct mlx4_dev *dev);
381 393
394void mlx4_do_sense_ports(struct mlx4_dev *dev,
395 enum mlx4_port_type *stype,
396 enum mlx4_port_type *defaults);
397void mlx4_start_sense(struct mlx4_dev *dev);
398void mlx4_stop_sense(struct mlx4_dev *dev);
399void mlx4_sense_init(struct mlx4_dev *dev);
400int mlx4_check_port_params(struct mlx4_dev *dev,
401 enum mlx4_port_type *port_type);
402int mlx4_change_port_types(struct mlx4_dev *dev,
403 enum mlx4_port_type *port_types);
404
382void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); 405void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
383void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); 406void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
384 407
diff --git a/drivers/net/mlx4/sense.c b/drivers/net/mlx4/sense.c
new file mode 100644
index 000000000000..6d5089ecb5af
--- /dev/null
+++ b/drivers/net/mlx4/sense.c
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) 2007 Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 *
32 */
33
34#include <linux/errno.h>
35#include <linux/if_ether.h>
36
37#include <linux/mlx4/cmd.h>
38
39#include "mlx4.h"
40
41static int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port,
42 enum mlx4_port_type *type)
43{
44 u64 out_param;
45 int err = 0;
46
47 err = mlx4_cmd_imm(dev, 0, &out_param, port, 0,
48 MLX4_CMD_SENSE_PORT, MLX4_CMD_TIME_CLASS_B);
49 if (err) {
50 mlx4_err(dev, "Sense command failed for port: %d\n", port);
51 return err;
52 }
53
54 if (out_param > 2) {
55 mlx4_err(dev, "Sense returned illegal value: 0x%llx\n", out_param);
56 return EINVAL;
57 }
58
59 *type = out_param;
60 return 0;
61}
62
63void mlx4_do_sense_ports(struct mlx4_dev *dev,
64 enum mlx4_port_type *stype,
65 enum mlx4_port_type *defaults)
66{
67 struct mlx4_sense *sense = &mlx4_priv(dev)->sense;
68 int err;
69 int i;
70
71 for (i = 1; i <= dev->caps.num_ports; i++) {
72 stype[i - 1] = 0;
73 if (sense->do_sense_port[i] && sense->sense_allowed[i] &&
74 dev->caps.possible_type[i] == MLX4_PORT_TYPE_AUTO) {
75 err = mlx4_SENSE_PORT(dev, i, &stype[i - 1]);
76 if (err)
77 stype[i - 1] = defaults[i - 1];
78 } else
79 stype[i - 1] = defaults[i - 1];
80 }
81
82 /*
83 * Adjust port configuration:
84 * If port 1 sensed nothing and port 2 is IB, set both as IB
85 * If port 2 sensed nothing and port 1 is Eth, set both as Eth
86 */
87 if (stype[0] == MLX4_PORT_TYPE_ETH) {
88 for (i = 1; i < dev->caps.num_ports; i++)
89 stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH;
90 }
91 if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) {
92 for (i = 0; i < dev->caps.num_ports - 1; i++)
93 stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB;
94 }
95
96 /*
97 * If sensed nothing, remain in current configuration.
98 */
99 for (i = 0; i < dev->caps.num_ports; i++)
100 stype[i] = stype[i] ? stype[i] : defaults[i];
101
102}
103
104static void mlx4_sense_port(struct work_struct *work)
105{
106 struct delayed_work *delay = container_of(work, struct delayed_work, work);
107 struct mlx4_sense *sense = container_of(delay, struct mlx4_sense,
108 sense_poll);
109 struct mlx4_dev *dev = sense->dev;
110 struct mlx4_priv *priv = mlx4_priv(dev);
111 enum mlx4_port_type stype[MLX4_MAX_PORTS];
112
113 mutex_lock(&priv->port_mutex);
114 mlx4_do_sense_ports(dev, stype, &dev->caps.port_type[1]);
115
116 if (mlx4_check_port_params(dev, stype))
117 goto sense_again;
118
119 if (mlx4_change_port_types(dev, stype))
120 mlx4_err(dev, "Failed to change port_types\n");
121
122sense_again:
123 mutex_unlock(&priv->port_mutex);
124 queue_delayed_work(mlx4_wq , &sense->sense_poll,
125 round_jiffies_relative(MLX4_SENSE_RANGE));
126}
127
128void mlx4_start_sense(struct mlx4_dev *dev)
129{
130 struct mlx4_priv *priv = mlx4_priv(dev);
131 struct mlx4_sense *sense = &priv->sense;
132
133 if (!(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP))
134 return;
135
136 queue_delayed_work(mlx4_wq , &sense->sense_poll,
137 round_jiffies_relative(MLX4_SENSE_RANGE));
138}
139
140void mlx4_stop_sense(struct mlx4_dev *dev)
141{
142 cancel_delayed_work_sync(&mlx4_priv(dev)->sense.sense_poll);
143}
144
145void mlx4_sense_init(struct mlx4_dev *dev)
146{
147 struct mlx4_priv *priv = mlx4_priv(dev);
148 struct mlx4_sense *sense = &priv->sense;
149 int port;
150
151 sense->dev = dev;
152 for (port = 1; port <= dev->caps.num_ports; port++)
153 sense->do_sense_port[port] = 1;
154
155 INIT_DELAYED_WORK_DEFERRABLE(&sense->sense_poll, mlx4_sense_port);
156}