diff options
Diffstat (limited to 'drivers/net/mlx4/main.c')
-rw-r--r-- | drivers/net/mlx4/main.c | 106 |
1 files changed, 79 insertions, 27 deletions
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 6ef2490d5c3e..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++) { |
@@ -1230,6 +1278,8 @@ static struct pci_device_id mlx4_pci_table[] = { | |||
1230 | { PCI_VDEVICE(MELLANOX, 0x673c) }, /* MT25408 "Hermon" QDR PCIe gen2 */ | 1278 | { PCI_VDEVICE(MELLANOX, 0x673c) }, /* MT25408 "Hermon" QDR PCIe gen2 */ |
1231 | { PCI_VDEVICE(MELLANOX, 0x6368) }, /* MT25408 "Hermon" EN 10GigE */ | 1279 | { PCI_VDEVICE(MELLANOX, 0x6368) }, /* MT25408 "Hermon" EN 10GigE */ |
1232 | { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ | 1280 | { PCI_VDEVICE(MELLANOX, 0x6750) }, /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ |
1281 | { PCI_VDEVICE(MELLANOX, 0x6372) }, /* MT25458 ConnectX EN 10GBASE-T 10GigE */ | ||
1282 | { PCI_VDEVICE(MELLANOX, 0x675a) }, /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ | ||
1233 | { 0, } | 1283 | { 0, } |
1234 | }; | 1284 | }; |
1235 | 1285 | ||
@@ -1264,9 +1314,11 @@ static int __init mlx4_init(void) | |||
1264 | if (mlx4_verify_params()) | 1314 | if (mlx4_verify_params()) |
1265 | return -EINVAL; | 1315 | return -EINVAL; |
1266 | 1316 | ||
1267 | ret = mlx4_catas_init(); | 1317 | mlx4_catas_init(); |
1268 | if (ret) | 1318 | |
1269 | return ret; | 1319 | mlx4_wq = create_singlethread_workqueue("mlx4"); |
1320 | if (!mlx4_wq) | ||
1321 | return -ENOMEM; | ||
1270 | 1322 | ||
1271 | ret = pci_register_driver(&mlx4_driver); | 1323 | ret = pci_register_driver(&mlx4_driver); |
1272 | return ret < 0 ? ret : 0; | 1324 | return ret < 0 ? ret : 0; |
@@ -1275,7 +1327,7 @@ static int __init mlx4_init(void) | |||
1275 | static void __exit mlx4_cleanup(void) | 1327 | static void __exit mlx4_cleanup(void) |
1276 | { | 1328 | { |
1277 | pci_unregister_driver(&mlx4_driver); | 1329 | pci_unregister_driver(&mlx4_driver); |
1278 | mlx4_catas_cleanup(); | 1330 | destroy_workqueue(mlx4_wq); |
1279 | } | 1331 | } |
1280 | 1332 | ||
1281 | module_init(mlx4_init); | 1333 | module_init(mlx4_init); |