aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArkadi Sharshevsky <arkadis@mellanox.com>2018-01-15 02:59:11 -0500
committerDavid S. Miller <davem@davemloft.net>2018-01-16 14:15:35 -0500
commit24cc68ad6c46f04f0206b41359e7af84e6dbde98 (patch)
tree1fcadd8fa956bddef4496c558599d3c693542565
parente21d21ca31f2fec31f9359a2209929a32a5faf9f (diff)
mlxsw: core: Add support for reload
Add support for hot reload. First, all the driver/core resources are released but the PCI and devlink instances, then reset is performed through the PCI interface. Finally the driver performs initialization. In case of reload failure the driver is left in a partially initialized state. Special care is taken during the driver removal in order to properly handle this state. Signed-off-by: Arkadi Sharshevsky <arkadis@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.c73
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/i2c.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/pci.c5
4 files changed, 65 insertions, 23 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c
index c93512b16121..3529b545675d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.c
@@ -113,6 +113,7 @@ struct mlxsw_core {
113 struct mlxsw_thermal *thermal; 113 struct mlxsw_thermal *thermal;
114 struct mlxsw_core_port *ports; 114 struct mlxsw_core_port *ports;
115 unsigned int max_ports; 115 unsigned int max_ports;
116 bool reload_fail;
116 unsigned long driver_priv[0]; 117 unsigned long driver_priv[0];
117 /* driver_priv has to be always the last item */ 118 /* driver_priv has to be always the last item */
118}; 119};
@@ -962,7 +963,28 @@ mlxsw_devlink_sb_occ_tc_port_bind_get(struct devlink_port *devlink_port,
962 pool_type, p_cur, p_max); 963 pool_type, p_cur, p_max);
963} 964}
964 965
966static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink)
967{
968 struct mlxsw_core *mlxsw_core = devlink_priv(devlink);
969 const struct mlxsw_bus *mlxsw_bus = mlxsw_core->bus;
970 int err;
971
972 if (!mlxsw_bus->reset)
973 return -EOPNOTSUPP;
974
975 mlxsw_core_bus_device_unregister(mlxsw_core, true);
976 mlxsw_bus->reset(mlxsw_core->bus_priv);
977 err = mlxsw_core_bus_device_register(mlxsw_core->bus_info,
978 mlxsw_core->bus,
979 mlxsw_core->bus_priv, true,
980 devlink);
981 if (err)
982 mlxsw_core->reload_fail = true;
983 return err;
984}
985
965static const struct devlink_ops mlxsw_devlink_ops = { 986static const struct devlink_ops mlxsw_devlink_ops = {
987 .reload = mlxsw_devlink_core_bus_device_reload,
966 .port_type_set = mlxsw_devlink_port_type_set, 988 .port_type_set = mlxsw_devlink_port_type_set,
967 .port_split = mlxsw_devlink_port_split, 989 .port_split = mlxsw_devlink_port_split,
968 .port_unsplit = mlxsw_devlink_port_unsplit, 990 .port_unsplit = mlxsw_devlink_port_unsplit,
@@ -980,23 +1002,26 @@ static const struct devlink_ops mlxsw_devlink_ops = {
980 1002
981int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, 1003int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
982 const struct mlxsw_bus *mlxsw_bus, 1004 const struct mlxsw_bus *mlxsw_bus,
983 void *bus_priv) 1005 void *bus_priv, bool reload,
1006 struct devlink *devlink)
984{ 1007{
985 const char *device_kind = mlxsw_bus_info->device_kind; 1008 const char *device_kind = mlxsw_bus_info->device_kind;
986 struct mlxsw_core *mlxsw_core; 1009 struct mlxsw_core *mlxsw_core;
987 struct mlxsw_driver *mlxsw_driver; 1010 struct mlxsw_driver *mlxsw_driver;
988 struct devlink *devlink;
989 size_t alloc_size; 1011 size_t alloc_size;
990 int err; 1012 int err;
991 1013
992 mlxsw_driver = mlxsw_core_driver_get(device_kind); 1014 mlxsw_driver = mlxsw_core_driver_get(device_kind);
993 if (!mlxsw_driver) 1015 if (!mlxsw_driver)
994 return -EINVAL; 1016 return -EINVAL;
995 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size; 1017
996 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size); 1018 if (!reload) {
997 if (!devlink) { 1019 alloc_size = sizeof(*mlxsw_core) + mlxsw_driver->priv_size;
998 err = -ENOMEM; 1020 devlink = devlink_alloc(&mlxsw_devlink_ops, alloc_size);
999 goto err_devlink_alloc; 1021 if (!devlink) {
1022 err = -ENOMEM;
1023 goto err_devlink_alloc;
1024 }
1000 } 1025 }
1001 1026
1002 mlxsw_core = devlink_priv(devlink); 1027 mlxsw_core = devlink_priv(devlink);
@@ -1012,7 +1037,7 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1012 if (err) 1037 if (err)
1013 goto err_bus_init; 1038 goto err_bus_init;
1014 1039
1015 if (mlxsw_driver->resources_register) { 1040 if (mlxsw_driver->resources_register && !reload) {
1016 err = mlxsw_driver->resources_register(mlxsw_core); 1041 err = mlxsw_driver->resources_register(mlxsw_core);
1017 if (err) 1042 if (err)
1018 goto err_register_resources; 1043 goto err_register_resources;
@@ -1038,9 +1063,11 @@ int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
1038 if (err) 1063 if (err)
1039 goto err_emad_init; 1064 goto err_emad_init;
1040 1065
1041 err = devlink_register(devlink, mlxsw_bus_info->dev); 1066 if (!reload) {
1042 if (err) 1067 err = devlink_register(devlink, mlxsw_bus_info->dev);
1043 goto err_devlink_register; 1068 if (err)
1069 goto err_devlink_register;
1070 }
1044 1071
1045 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon); 1072 err = mlxsw_hwmon_init(mlxsw_core, mlxsw_bus_info, &mlxsw_core->hwmon);
1046 if (err) 1073 if (err)
@@ -1063,7 +1090,8 @@ err_driver_init:
1063 mlxsw_thermal_fini(mlxsw_core->thermal); 1090 mlxsw_thermal_fini(mlxsw_core->thermal);
1064err_thermal_init: 1091err_thermal_init:
1065err_hwmon_init: 1092err_hwmon_init:
1066 devlink_unregister(devlink); 1093 if (!reload)
1094 devlink_unregister(devlink);
1067err_devlink_register: 1095err_devlink_register:
1068 mlxsw_emad_fini(mlxsw_core); 1096 mlxsw_emad_fini(mlxsw_core);
1069err_emad_init: 1097err_emad_init:
@@ -1073,29 +1101,40 @@ err_alloc_lag_mapping:
1073err_ports_init: 1101err_ports_init:
1074 mlxsw_bus->fini(bus_priv); 1102 mlxsw_bus->fini(bus_priv);
1075err_bus_init: 1103err_bus_init:
1076 devlink_resources_unregister(devlink, NULL); 1104 if (!reload)
1105 devlink_resources_unregister(devlink, NULL);
1077err_register_resources: 1106err_register_resources:
1078 devlink_free(devlink); 1107 if (!reload)
1108 devlink_free(devlink);
1079err_devlink_alloc: 1109err_devlink_alloc:
1080 mlxsw_core_driver_put(device_kind); 1110 mlxsw_core_driver_put(device_kind);
1081 return err; 1111 return err;
1082} 1112}
1083EXPORT_SYMBOL(mlxsw_core_bus_device_register); 1113EXPORT_SYMBOL(mlxsw_core_bus_device_register);
1084 1114
1085void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core) 1115void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core,
1116 bool reload)
1086{ 1117{
1087 const char *device_kind = mlxsw_core->bus_info->device_kind; 1118 const char *device_kind = mlxsw_core->bus_info->device_kind;
1088 struct devlink *devlink = priv_to_devlink(mlxsw_core); 1119 struct devlink *devlink = priv_to_devlink(mlxsw_core);
1089 1120
1121 if (mlxsw_core->reload_fail)
1122 goto reload_fail;
1123
1090 if (mlxsw_core->driver->fini) 1124 if (mlxsw_core->driver->fini)
1091 mlxsw_core->driver->fini(mlxsw_core); 1125 mlxsw_core->driver->fini(mlxsw_core);
1092 mlxsw_thermal_fini(mlxsw_core->thermal); 1126 mlxsw_thermal_fini(mlxsw_core->thermal);
1093 devlink_unregister(devlink); 1127 if (!reload)
1128 devlink_unregister(devlink);
1094 mlxsw_emad_fini(mlxsw_core); 1129 mlxsw_emad_fini(mlxsw_core);
1095 kfree(mlxsw_core->lag.mapping); 1130 kfree(mlxsw_core->lag.mapping);
1096 mlxsw_ports_fini(mlxsw_core); 1131 mlxsw_ports_fini(mlxsw_core);
1097 devlink_resources_unregister(devlink, NULL); 1132 if (!reload)
1133 devlink_resources_unregister(devlink, NULL);
1098 mlxsw_core->bus->fini(mlxsw_core->bus_priv); 1134 mlxsw_core->bus->fini(mlxsw_core->bus_priv);
1135 if (reload)
1136 return;
1137reload_fail:
1099 devlink_free(devlink); 1138 devlink_free(devlink);
1100 mlxsw_core_driver_put(device_kind); 1139 mlxsw_core_driver_put(device_kind);
1101} 1140}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h
index e44061dfe8c7..5ddafd74dc00 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core.h
@@ -66,8 +66,9 @@ void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver);
66 66
67int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, 67int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info,
68 const struct mlxsw_bus *mlxsw_bus, 68 const struct mlxsw_bus *mlxsw_bus,
69 void *bus_priv); 69 void *bus_priv, bool reload,
70void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core); 70 struct devlink *devlink);
71void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, bool reload);
71 72
72struct mlxsw_tx_info { 73struct mlxsw_tx_info {
73 u8 local_port; 74 u8 local_port;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
index c0dcfa05b077..25f9915ebd82 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c
@@ -539,7 +539,8 @@ static int mlxsw_i2c_probe(struct i2c_client *client,
539 mlxsw_i2c->dev = &client->dev; 539 mlxsw_i2c->dev = &client->dev;
540 540
541 err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, 541 err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info,
542 &mlxsw_i2c_bus, mlxsw_i2c); 542 &mlxsw_i2c_bus, mlxsw_i2c, false,
543 NULL);
543 if (err) { 544 if (err) {
544 dev_err(&client->dev, "Fail to register core bus\n"); 545 dev_err(&client->dev, "Fail to register core bus\n");
545 return err; 546 return err;
@@ -557,7 +558,7 @@ static int mlxsw_i2c_remove(struct i2c_client *client)
557{ 558{
558 struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); 559 struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client);
559 560
560 mlxsw_core_bus_device_unregister(mlxsw_i2c->core); 561 mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false);
561 mutex_destroy(&mlxsw_i2c->cmd.lock); 562 mutex_destroy(&mlxsw_i2c->cmd.lock);
562 563
563 return 0; 564 return 0;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c
index 58ab18845928..85faa87bf42d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c
@@ -1739,7 +1739,8 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1739 mlxsw_pci->id = id; 1739 mlxsw_pci->id = id;
1740 1740
1741 err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info, 1741 err = mlxsw_core_bus_device_register(&mlxsw_pci->bus_info,
1742 &mlxsw_pci_bus, mlxsw_pci); 1742 &mlxsw_pci_bus, mlxsw_pci, false,
1743 NULL);
1743 if (err) { 1744 if (err) {
1744 dev_err(&pdev->dev, "cannot register bus device\n"); 1745 dev_err(&pdev->dev, "cannot register bus device\n");
1745 goto err_bus_device_register; 1746 goto err_bus_device_register;
@@ -1767,7 +1768,7 @@ static void mlxsw_pci_remove(struct pci_dev *pdev)
1767{ 1768{
1768 struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev); 1769 struct mlxsw_pci *mlxsw_pci = pci_get_drvdata(pdev);
1769 1770
1770 mlxsw_core_bus_device_unregister(mlxsw_pci->core); 1771 mlxsw_core_bus_device_unregister(mlxsw_pci->core, false);
1771 mlxsw_pci_free_irq_vectors(mlxsw_pci); 1772 mlxsw_pci_free_irq_vectors(mlxsw_pci);
1772 iounmap(mlxsw_pci->hw_addr); 1773 iounmap(mlxsw_pci->hw_addr);
1773 pci_release_regions(mlxsw_pci->pdev); 1774 pci_release_regions(mlxsw_pci->pdev);