aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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}