Skip to content

Commit 1ecd749

Browse files
committed
Merge branch 'preserve-pse-pd692x0-configuration-across-reboots'
Kory Maincent says: ==================== Preserve PSE PD692x0 configuration across reboots Previously, the driver would always reconfigure the PSE hardware on probe, causing a port matrix reflash that resulted in temporary power loss to all connected devices. This change maintains power continuity by preserving existing configuration when the PSE has been previously initialized. ==================== Link: https://patch.msgid.link/20251013-feature_pd692x0_reboot_keep_conf-v2-0-68ab082a93dd@bootlin.com Signed-off-by: Jakub Kicinski <[email protected]>
2 parents e1f5bb1 + 8f3d044 commit 1ecd749

File tree

1 file changed

+112
-43
lines changed

1 file changed

+112
-43
lines changed

drivers/net/pse-pd/pd692x0.c

Lines changed: 112 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#define PD692X0_FW_MIN_VER 5
3131
#define PD692X0_FW_PATCH_VER 5
3232

33+
#define PD692X0_USER_BYTE 42
34+
3335
enum pd692x0_fw_state {
3436
PD692X0_FW_UNKNOWN,
3537
PD692X0_FW_OK,
@@ -80,11 +82,17 @@ enum {
8082
PD692X0_MSG_GET_PORT_PARAM,
8183
PD692X0_MSG_GET_POWER_BANK,
8284
PD692X0_MSG_SET_POWER_BANK,
85+
PD692X0_MSG_SET_USER_BYTE,
8386

8487
/* add new message above here */
8588
PD692X0_MSG_CNT
8689
};
8790

91+
struct pd692x0_matrix {
92+
u8 hw_port_a;
93+
u8 hw_port_b;
94+
};
95+
8896
struct pd692x0_priv {
8997
struct i2c_client *client;
9098
struct pse_controller_dev pcdev;
@@ -98,9 +106,12 @@ struct pd692x0_priv {
98106
bool last_cmd_key;
99107
unsigned long last_cmd_key_time;
100108

109+
bool cfg_saved;
101110
enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS];
102111
struct regulator_dev *manager_reg[PD692X0_MAX_MANAGERS];
103112
int manager_pw_budget[PD692X0_MAX_MANAGERS];
113+
int nmanagers;
114+
struct pd692x0_matrix *port_matrix;
104115
};
105116

106117
/* Template list of communication messages. The non-null bytes defined here
@@ -186,6 +197,12 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = {
186197
.key = PD692X0_KEY_CMD,
187198
.sub = {0x07, 0x0b, 0x57},
188199
},
200+
[PD692X0_MSG_SET_USER_BYTE] = {
201+
.key = PD692X0_KEY_PRG,
202+
.sub = {0x41, PD692X0_USER_BYTE},
203+
.data = {0x4e, 0x4e, 0x4e, 0x4e,
204+
0x4e, 0x4e, 0x4e, 0x4e},
205+
},
189206
};
190207

191208
static u8 pd692x0_build_msg(struct pd692x0_msg *msg, u8 echo)
@@ -809,11 +826,6 @@ struct pd692x0_manager {
809826
int nports;
810827
};
811828

812-
struct pd692x0_matrix {
813-
u8 hw_port_a;
814-
u8 hw_port_b;
815-
};
816-
817829
static int
818830
pd692x0_of_get_ports_manager(struct pd692x0_priv *priv,
819831
struct pd692x0_manager *manager,
@@ -903,7 +915,8 @@ pd692x0_of_get_managers(struct pd692x0_priv *priv,
903915
}
904916

905917
of_node_put(managers_node);
906-
return nmanagers;
918+
priv->nmanagers = nmanagers;
919+
return 0;
907920

908921
out:
909922
for (i = 0; i < nmanagers; i++) {
@@ -963,8 +976,7 @@ pd692x0_register_manager_regulator(struct device *dev, char *reg_name,
963976

964977
static int
965978
pd692x0_register_managers_regulator(struct pd692x0_priv *priv,
966-
const struct pd692x0_manager *manager,
967-
int nmanagers)
979+
const struct pd692x0_manager *manager)
968980
{
969981
struct device *dev = &priv->client->dev;
970982
size_t reg_name_len;
@@ -975,7 +987,7 @@ pd692x0_register_managers_regulator(struct pd692x0_priv *priv,
975987
*/
976988
reg_name_len = strlen(dev_name(dev)) + 23;
977989

978-
for (i = 0; i < nmanagers; i++) {
990+
for (i = 0; i < priv->nmanagers; i++) {
979991
static const char * const regulators[] = { "vaux5", "vaux3p3" };
980992
struct regulator_dev *rdev;
981993
char *reg_name;
@@ -1008,10 +1020,14 @@ pd692x0_register_managers_regulator(struct pd692x0_priv *priv,
10081020
}
10091021

10101022
static int
1011-
pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int pw)
1023+
pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id)
10121024
{
10131025
struct pd692x0_msg msg, buf;
1014-
int ret, pw_mW = pw / 1000;
1026+
int ret, pw_mW;
1027+
1028+
pw_mW = priv->manager_pw_budget[id] / 1000;
1029+
if (!pw_mW)
1030+
return 0;
10151031

10161032
msg = pd692x0_msg_template_list[PD692X0_MSG_GET_POWER_BANK];
10171033
msg.data[0] = id;
@@ -1032,11 +1048,11 @@ pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int pw)
10321048
}
10331049

10341050
static int
1035-
pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers)
1051+
pd692x0_req_managers_pw_budget(struct pd692x0_priv *priv)
10361052
{
10371053
int i, ret;
10381054

1039-
for (i = 0; i < nmanagers; i++) {
1055+
for (i = 0; i < priv->nmanagers; i++) {
10401056
struct regulator *supply = priv->manager_reg[i]->supply;
10411057
int pw_budget;
10421058

@@ -1053,7 +1069,18 @@ pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers)
10531069
return ret;
10541070

10551071
priv->manager_pw_budget[i] = pw_budget;
1056-
ret = pd692x0_conf_manager_power_budget(priv, i, pw_budget);
1072+
}
1073+
1074+
return 0;
1075+
}
1076+
1077+
static int
1078+
pd692x0_configure_managers(struct pd692x0_priv *priv)
1079+
{
1080+
int i, ret;
1081+
1082+
for (i = 0; i < priv->nmanagers; i++) {
1083+
ret = pd692x0_conf_manager_power_budget(priv, i);
10571084
if (ret < 0)
10581085
return ret;
10591086
}
@@ -1101,10 +1128,9 @@ pd692x0_set_port_matrix(const struct pse_pi_pairset *pairset,
11011128

11021129
static int
11031130
pd692x0_set_ports_matrix(struct pd692x0_priv *priv,
1104-
const struct pd692x0_manager *manager,
1105-
int nmanagers,
1106-
struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])
1131+
const struct pd692x0_manager *manager)
11071132
{
1133+
struct pd692x0_matrix *port_matrix = priv->port_matrix;
11081134
struct pse_controller_dev *pcdev = &priv->pcdev;
11091135
int i, ret;
11101136

@@ -1117,7 +1143,7 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv,
11171143
/* Update with values for every PSE PIs */
11181144
for (i = 0; i < pcdev->nr_lines; i++) {
11191145
ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[0],
1120-
manager, nmanagers,
1146+
manager, priv->nmanagers,
11211147
&port_matrix[i]);
11221148
if (ret) {
11231149
dev_err(&priv->client->dev,
@@ -1126,7 +1152,7 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv,
11261152
}
11271153

11281154
ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[1],
1129-
manager, nmanagers,
1155+
manager, priv->nmanagers,
11301156
&port_matrix[i]);
11311157
if (ret) {
11321158
dev_err(&priv->client->dev,
@@ -1139,9 +1165,9 @@ pd692x0_set_ports_matrix(struct pd692x0_priv *priv,
11391165
}
11401166

11411167
static int
1142-
pd692x0_write_ports_matrix(struct pd692x0_priv *priv,
1143-
const struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS])
1168+
pd692x0_write_ports_matrix(struct pd692x0_priv *priv)
11441169
{
1170+
struct pd692x0_matrix *port_matrix = priv->port_matrix;
11451171
struct pd692x0_msg msg, buf;
11461172
int ret, i;
11471173

@@ -1166,13 +1192,32 @@ pd692x0_write_ports_matrix(struct pd692x0_priv *priv,
11661192
return 0;
11671193
}
11681194

1195+
static int pd692x0_hw_conf_init(struct pd692x0_priv *priv)
1196+
{
1197+
int ret;
1198+
1199+
/* Is PD692x0 ready to be configured? */
1200+
if (priv->fw_state != PD692X0_FW_OK &&
1201+
priv->fw_state != PD692X0_FW_COMPLETE)
1202+
return 0;
1203+
1204+
ret = pd692x0_configure_managers(priv);
1205+
if (ret)
1206+
return ret;
1207+
1208+
ret = pd692x0_write_ports_matrix(priv);
1209+
if (ret)
1210+
return ret;
1211+
1212+
return 0;
1213+
}
1214+
11691215
static void pd692x0_of_put_managers(struct pd692x0_priv *priv,
1170-
struct pd692x0_manager *manager,
1171-
int nmanagers)
1216+
struct pd692x0_manager *manager)
11721217
{
11731218
int i, j;
11741219

1175-
for (i = 0; i < nmanagers; i++) {
1220+
for (i = 0; i < priv->nmanagers; i++) {
11761221
for (j = 0; j < manager[i].nports; j++)
11771222
of_node_put(manager[i].port_node[j]);
11781223
of_node_put(manager[i].node);
@@ -1198,50 +1243,71 @@ static void pd692x0_managers_free_pw_budget(struct pd692x0_priv *priv)
11981243
}
11991244
}
12001245

1246+
static int
1247+
pd692x0_save_user_byte(struct pd692x0_priv *priv)
1248+
{
1249+
struct pd692x0_msg msg, buf;
1250+
1251+
msg = pd692x0_msg_template_list[PD692X0_MSG_SET_USER_BYTE];
1252+
return pd692x0_sendrecv_msg(priv, &msg, &buf);
1253+
}
1254+
12011255
static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev)
12021256
{
1203-
struct pd692x0_manager *manager __free(kfree) = NULL;
12041257
struct pd692x0_priv *priv = to_pd692x0_priv(pcdev);
1205-
struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS];
1206-
int ret, nmanagers;
1207-
1208-
/* Should we flash the port matrix */
1209-
if (priv->fw_state != PD692X0_FW_OK &&
1210-
priv->fw_state != PD692X0_FW_COMPLETE)
1211-
return 0;
1258+
struct pd692x0_matrix *port_matrix;
1259+
struct pd692x0_manager *manager;
1260+
int ret;
12121261

12131262
manager = kcalloc(PD692X0_MAX_MANAGERS, sizeof(*manager), GFP_KERNEL);
12141263
if (!manager)
12151264
return -ENOMEM;
12161265

1266+
port_matrix = devm_kcalloc(&priv->client->dev, PD692X0_MAX_PIS,
1267+
sizeof(*port_matrix), GFP_KERNEL);
1268+
if (!port_matrix) {
1269+
ret = -ENOMEM;
1270+
goto err_free_manager;
1271+
}
1272+
priv->port_matrix = port_matrix;
1273+
12171274
ret = pd692x0_of_get_managers(priv, manager);
12181275
if (ret < 0)
1219-
return ret;
1276+
goto err_free_manager;
12201277

1221-
nmanagers = ret;
1222-
ret = pd692x0_register_managers_regulator(priv, manager, nmanagers);
1278+
ret = pd692x0_register_managers_regulator(priv, manager);
12231279
if (ret)
12241280
goto err_of_managers;
12251281

1226-
ret = pd692x0_configure_managers(priv, nmanagers);
1282+
ret = pd692x0_req_managers_pw_budget(priv);
12271283
if (ret)
12281284
goto err_of_managers;
12291285

1230-
ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix);
1286+
ret = pd692x0_set_ports_matrix(priv, manager);
12311287
if (ret)
12321288
goto err_managers_req_pw;
12331289

1234-
ret = pd692x0_write_ports_matrix(priv, port_matrix);
1235-
if (ret)
1236-
goto err_managers_req_pw;
1290+
/* Do not init the conf if it is already saved */
1291+
if (!priv->cfg_saved) {
1292+
ret = pd692x0_hw_conf_init(priv);
1293+
if (ret)
1294+
goto err_managers_req_pw;
12371295

1238-
pd692x0_of_put_managers(priv, manager, nmanagers);
1296+
ret = pd692x0_save_user_byte(priv);
1297+
if (ret)
1298+
goto err_managers_req_pw;
1299+
}
1300+
1301+
pd692x0_of_put_managers(priv, manager);
1302+
kfree(manager);
12391303
return 0;
12401304

12411305
err_managers_req_pw:
12421306
pd692x0_managers_free_pw_budget(priv);
12431307
err_of_managers:
1244-
pd692x0_of_put_managers(priv, manager, nmanagers);
1308+
pd692x0_of_put_managers(priv, manager);
1309+
err_free_manager:
1310+
kfree(manager);
12451311
return ret;
12461312
}
12471313

@@ -1644,7 +1710,7 @@ static enum fw_upload_err pd692x0_fw_poll_complete(struct fw_upload *fwl)
16441710
return FW_UPLOAD_ERR_FW_INVALID;
16451711
}
16461712

1647-
ret = pd692x0_setup_pi_matrix(&priv->pcdev);
1713+
ret = pd692x0_hw_conf_init(priv);
16481714
if (ret < 0) {
16491715
dev_err(&client->dev, "Error configuring ports matrix (%pe)\n",
16501716
ERR_PTR(ret));
@@ -1753,6 +1819,9 @@ static int pd692x0_i2c_probe(struct i2c_client *client)
17531819
}
17541820
}
17551821

1822+
if (buf.data[2] == PD692X0_USER_BYTE)
1823+
priv->cfg_saved = true;
1824+
17561825
priv->np = dev->of_node;
17571826
priv->pcdev.nr_lines = PD692X0_MAX_PIS;
17581827
priv->pcdev.owner = THIS_MODULE;

0 commit comments

Comments
 (0)