diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/mlx4/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/mlx4/catas.c | 16 | ||||
-rw-r--r-- | drivers/net/mlx4/eq.c | 16 | ||||
-rw-r--r-- | drivers/net/mlx4/main.c | 104 | ||||
-rw-r--r-- | drivers/net/mlx4/mlx4.h | 27 | ||||
-rw-r--r-- | drivers/net/mlx4/sense.c | 156 |
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 @@ | |||
1 | obj-$(CONFIG_MLX4_CORE) += mlx4_core.o | 1 | obj-$(CONFIG_MLX4_CORE) += mlx4_core.o |
2 | 2 | ||
3 | mlx4_core-y := alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \ | 3 | mlx4_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 | ||
6 | obj-$(CONFIG_MLX4_EN) += mlx4_en.o | 6 | obj-$(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 { | |||
42 | static DEFINE_SPINLOCK(catas_lock); | 42 | static DEFINE_SPINLOCK(catas_lock); |
43 | 43 | ||
44 | static LIST_HEAD(catas_list); | 44 | static LIST_HEAD(catas_list); |
45 | static struct workqueue_struct *catas_wq; | ||
46 | static struct work_struct catas_work; | 45 | static struct work_struct catas_work; |
47 | 46 | ||
48 | static int internal_err_reset = 1; | 47 | static 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 | ||
149 | int __init mlx4_catas_init(void) | 148 | void __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 | |||
160 | void 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"); | |||
51 | MODULE_LICENSE("Dual BSD/GPL"); | 51 | MODULE_LICENSE("Dual BSD/GPL"); |
52 | MODULE_VERSION(DRV_VERSION); | 52 | MODULE_VERSION(DRV_VERSION); |
53 | 53 | ||
54 | struct workqueue_struct *mlx4_wq; | ||
55 | |||
54 | #ifdef CONFIG_MLX4_DEBUG | 56 | #ifdef CONFIG_MLX4_DEBUG |
55 | 57 | ||
56 | int mlx4_debug_level = 0; | 58 | int mlx4_debug_level = 0; |
@@ -98,24 +100,23 @@ module_param_named(use_prio, use_prio, bool, 0444); | |||
98 | MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports " | 100 | MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports " |
99 | "(0/1, default 0)"); | 101 | "(0/1, default 0)"); |
100 | 102 | ||
101 | static int mlx4_check_port_params(struct mlx4_dev *dev, | 103 | int 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 | */ |
266 | static int mlx4_change_port_types(struct mlx4_dev *dev, | 270 | int 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 | ||
311 | static ssize_t set_port_type(struct device *dev, | 324 | static 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 | ||
346 | out: | 389 | out: |
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) | |||
1277 | static void __exit mlx4_cleanup(void) | 1327 | static 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 | ||
1283 | module_init(mlx4_init); | 1333 | module_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 | ||
280 | struct 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 | |||
279 | struct mlx4_priv { | 287 | struct 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 | |||
327 | extern struct workqueue_struct *mlx4_wq; | ||
328 | |||
316 | u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); | 329 | u32 mlx4_bitmap_alloc(struct mlx4_bitmap *bitmap); |
317 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); | 330 | void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj); |
318 | u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align); | 331 | u32 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 | ||
347 | void mlx4_start_catas_poll(struct mlx4_dev *dev); | 360 | void mlx4_start_catas_poll(struct mlx4_dev *dev); |
348 | void mlx4_stop_catas_poll(struct mlx4_dev *dev); | 361 | void mlx4_stop_catas_poll(struct mlx4_dev *dev); |
349 | int mlx4_catas_init(void); | 362 | void mlx4_catas_init(void); |
350 | void mlx4_catas_cleanup(void); | ||
351 | int mlx4_restart_one(struct pci_dev *pdev); | 363 | int mlx4_restart_one(struct pci_dev *pdev); |
352 | int mlx4_register_device(struct mlx4_dev *dev); | 364 | int mlx4_register_device(struct mlx4_dev *dev); |
353 | void mlx4_unregister_device(struct mlx4_dev *dev); | 365 | void 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 | ||
380 | void mlx4_handle_catas_err(struct mlx4_dev *dev); | 392 | void mlx4_handle_catas_err(struct mlx4_dev *dev); |
381 | 393 | ||
394 | void mlx4_do_sense_ports(struct mlx4_dev *dev, | ||
395 | enum mlx4_port_type *stype, | ||
396 | enum mlx4_port_type *defaults); | ||
397 | void mlx4_start_sense(struct mlx4_dev *dev); | ||
398 | void mlx4_stop_sense(struct mlx4_dev *dev); | ||
399 | void mlx4_sense_init(struct mlx4_dev *dev); | ||
400 | int mlx4_check_port_params(struct mlx4_dev *dev, | ||
401 | enum mlx4_port_type *port_type); | ||
402 | int mlx4_change_port_types(struct mlx4_dev *dev, | ||
403 | enum mlx4_port_type *port_types); | ||
404 | |||
382 | void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); | 405 | void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); |
383 | void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); | 406 | void 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 | |||
41 | static 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 | |||
63 | void 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 | |||
104 | static 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 | |||
122 | sense_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 | |||
128 | void 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 | |||
140 | void mlx4_stop_sense(struct mlx4_dev *dev) | ||
141 | { | ||
142 | cancel_delayed_work_sync(&mlx4_priv(dev)->sense.sense_poll); | ||
143 | } | ||
144 | |||
145 | void 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 | } | ||