diff options
| -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 | ||||
| -rw-r--r-- | include/linux/mlx4/cmd.h | 1 | ||||
| -rw-r--r-- | include/linux/mlx4/device.h | 6 |
8 files changed, 277 insertions, 51 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 | } | ||
diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index cf9c679ab38b..0f82293a82ed 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h | |||
| @@ -55,6 +55,7 @@ enum { | |||
| 55 | MLX4_CMD_CLOSE_PORT = 0xa, | 55 | MLX4_CMD_CLOSE_PORT = 0xa, |
| 56 | MLX4_CMD_QUERY_HCA = 0xb, | 56 | MLX4_CMD_QUERY_HCA = 0xb, |
| 57 | MLX4_CMD_QUERY_PORT = 0x43, | 57 | MLX4_CMD_QUERY_PORT = 0x43, |
| 58 | MLX4_CMD_SENSE_PORT = 0x4d, | ||
| 58 | MLX4_CMD_SET_PORT = 0xc, | 59 | MLX4_CMD_SET_PORT = 0xc, |
| 59 | MLX4_CMD_ACCESS_DDR = 0x2e, | 60 | MLX4_CMD_ACCESS_DDR = 0x2e, |
| 60 | MLX4_CMD_MAP_ICM = 0xffa, | 61 | MLX4_CMD_MAP_ICM = 0xffa, |
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 8f659cc29960..3aff8a6a389e 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
| @@ -155,8 +155,9 @@ enum mlx4_qp_region { | |||
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | enum mlx4_port_type { | 157 | enum mlx4_port_type { |
| 158 | MLX4_PORT_TYPE_IB = 1 << 0, | 158 | MLX4_PORT_TYPE_IB = 1, |
| 159 | MLX4_PORT_TYPE_ETH = 1 << 1, | 159 | MLX4_PORT_TYPE_ETH = 2, |
| 160 | MLX4_PORT_TYPE_AUTO = 3 | ||
| 160 | }; | 161 | }; |
| 161 | 162 | ||
| 162 | enum mlx4_special_vlan_idx { | 163 | enum mlx4_special_vlan_idx { |
| @@ -237,6 +238,7 @@ struct mlx4_caps { | |||
| 237 | enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; | 238 | enum mlx4_port_type port_type[MLX4_MAX_PORTS + 1]; |
| 238 | u8 supported_type[MLX4_MAX_PORTS + 1]; | 239 | u8 supported_type[MLX4_MAX_PORTS + 1]; |
| 239 | u32 port_mask; | 240 | u32 port_mask; |
| 241 | enum mlx4_port_type possible_type[MLX4_MAX_PORTS + 1]; | ||
| 240 | }; | 242 | }; |
| 241 | 243 | ||
| 242 | struct mlx4_buf_list { | 244 | struct mlx4_buf_list { |
