Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <kuba@kernel.org>

+112 -43
+112 -43
drivers/net/pse-pd/pd692x0.c
··· 30 30 #define PD692X0_FW_MIN_VER 5 31 31 #define PD692X0_FW_PATCH_VER 5 32 32 33 + #define PD692X0_USER_BYTE 42 34 + 33 35 enum pd692x0_fw_state { 34 36 PD692X0_FW_UNKNOWN, 35 37 PD692X0_FW_OK, ··· 82 80 PD692X0_MSG_GET_PORT_PARAM, 83 81 PD692X0_MSG_GET_POWER_BANK, 84 82 PD692X0_MSG_SET_POWER_BANK, 83 + PD692X0_MSG_SET_USER_BYTE, 85 84 86 85 /* add new message above here */ 87 86 PD692X0_MSG_CNT 87 + }; 88 + 89 + struct pd692x0_matrix { 90 + u8 hw_port_a; 91 + u8 hw_port_b; 88 92 }; 89 93 90 94 struct pd692x0_priv { ··· 106 98 bool last_cmd_key; 107 99 unsigned long last_cmd_key_time; 108 100 101 + bool cfg_saved; 109 102 enum ethtool_c33_pse_admin_state admin_state[PD692X0_MAX_PIS]; 110 103 struct regulator_dev *manager_reg[PD692X0_MAX_MANAGERS]; 111 104 int manager_pw_budget[PD692X0_MAX_MANAGERS]; 105 + int nmanagers; 106 + struct pd692x0_matrix *port_matrix; 112 107 }; 113 108 114 109 /* Template list of communication messages. The non-null bytes defined here ··· 196 185 [PD692X0_MSG_SET_POWER_BANK] = { 197 186 .key = PD692X0_KEY_CMD, 198 187 .sub = {0x07, 0x0b, 0x57}, 188 + }, 189 + [PD692X0_MSG_SET_USER_BYTE] = { 190 + .key = PD692X0_KEY_PRG, 191 + .sub = {0x41, PD692X0_USER_BYTE}, 192 + .data = {0x4e, 0x4e, 0x4e, 0x4e, 193 + 0x4e, 0x4e, 0x4e, 0x4e}, 199 194 }, 200 195 }; 201 196 ··· 826 809 int nports; 827 810 }; 828 811 829 - struct pd692x0_matrix { 830 - u8 hw_port_a; 831 - u8 hw_port_b; 832 - }; 833 - 834 812 static int 835 813 pd692x0_of_get_ports_manager(struct pd692x0_priv *priv, 836 814 struct pd692x0_manager *manager, ··· 915 903 } 916 904 917 905 of_node_put(managers_node); 918 - return nmanagers; 906 + priv->nmanagers = nmanagers; 907 + return 0; 919 908 920 909 out: 921 910 for (i = 0; i < nmanagers; i++) { ··· 976 963 977 964 static int 978 965 pd692x0_register_managers_regulator(struct pd692x0_priv *priv, 979 - const struct pd692x0_manager *manager, 980 - int nmanagers) 966 + const struct pd692x0_manager *manager) 981 967 { 982 968 struct device *dev = &priv->client->dev; 983 969 size_t reg_name_len; ··· 987 975 */ 988 976 reg_name_len = strlen(dev_name(dev)) + 23; 989 977 990 - for (i = 0; i < nmanagers; i++) { 978 + for (i = 0; i < priv->nmanagers; i++) { 991 979 static const char * const regulators[] = { "vaux5", "vaux3p3" }; 992 980 struct regulator_dev *rdev; 993 981 char *reg_name; ··· 1020 1008 } 1021 1009 1022 1010 static int 1023 - pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id, int pw) 1011 + pd692x0_conf_manager_power_budget(struct pd692x0_priv *priv, int id) 1024 1012 { 1025 1013 struct pd692x0_msg msg, buf; 1026 - int ret, pw_mW = pw / 1000; 1014 + int ret, pw_mW; 1015 + 1016 + pw_mW = priv->manager_pw_budget[id] / 1000; 1017 + if (!pw_mW) 1018 + return 0; 1027 1019 1028 1020 msg = pd692x0_msg_template_list[PD692X0_MSG_GET_POWER_BANK]; 1029 1021 msg.data[0] = id; ··· 1048 1032 } 1049 1033 1050 1034 static int 1051 - pd692x0_configure_managers(struct pd692x0_priv *priv, int nmanagers) 1035 + pd692x0_req_managers_pw_budget(struct pd692x0_priv *priv) 1052 1036 { 1053 1037 int i, ret; 1054 1038 1055 - for (i = 0; i < nmanagers; i++) { 1039 + for (i = 0; i < priv->nmanagers; i++) { 1056 1040 struct regulator *supply = priv->manager_reg[i]->supply; 1057 1041 int pw_budget; 1058 1042 ··· 1069 1053 return ret; 1070 1054 1071 1055 priv->manager_pw_budget[i] = pw_budget; 1072 - ret = pd692x0_conf_manager_power_budget(priv, i, pw_budget); 1056 + } 1057 + 1058 + return 0; 1059 + } 1060 + 1061 + static int 1062 + pd692x0_configure_managers(struct pd692x0_priv *priv) 1063 + { 1064 + int i, ret; 1065 + 1066 + for (i = 0; i < priv->nmanagers; i++) { 1067 + ret = pd692x0_conf_manager_power_budget(priv, i); 1073 1068 if (ret < 0) 1074 1069 return ret; 1075 1070 } ··· 1128 1101 1129 1102 static int 1130 1103 pd692x0_set_ports_matrix(struct pd692x0_priv *priv, 1131 - const struct pd692x0_manager *manager, 1132 - int nmanagers, 1133 - struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]) 1104 + const struct pd692x0_manager *manager) 1134 1105 { 1106 + struct pd692x0_matrix *port_matrix = priv->port_matrix; 1135 1107 struct pse_controller_dev *pcdev = &priv->pcdev; 1136 1108 int i, ret; 1137 1109 ··· 1143 1117 /* Update with values for every PSE PIs */ 1144 1118 for (i = 0; i < pcdev->nr_lines; i++) { 1145 1119 ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[0], 1146 - manager, nmanagers, 1120 + manager, priv->nmanagers, 1147 1121 &port_matrix[i]); 1148 1122 if (ret) { 1149 1123 dev_err(&priv->client->dev, ··· 1152 1126 } 1153 1127 1154 1128 ret = pd692x0_set_port_matrix(&pcdev->pi[i].pairset[1], 1155 - manager, nmanagers, 1129 + manager, priv->nmanagers, 1156 1130 &port_matrix[i]); 1157 1131 if (ret) { 1158 1132 dev_err(&priv->client->dev, ··· 1165 1139 } 1166 1140 1167 1141 static int 1168 - pd692x0_write_ports_matrix(struct pd692x0_priv *priv, 1169 - const struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]) 1142 + pd692x0_write_ports_matrix(struct pd692x0_priv *priv) 1170 1143 { 1144 + struct pd692x0_matrix *port_matrix = priv->port_matrix; 1171 1145 struct pd692x0_msg msg, buf; 1172 1146 int ret, i; 1173 1147 ··· 1192 1166 return 0; 1193 1167 } 1194 1168 1169 + static int pd692x0_hw_conf_init(struct pd692x0_priv *priv) 1170 + { 1171 + int ret; 1172 + 1173 + /* Is PD692x0 ready to be configured? */ 1174 + if (priv->fw_state != PD692X0_FW_OK && 1175 + priv->fw_state != PD692X0_FW_COMPLETE) 1176 + return 0; 1177 + 1178 + ret = pd692x0_configure_managers(priv); 1179 + if (ret) 1180 + return ret; 1181 + 1182 + ret = pd692x0_write_ports_matrix(priv); 1183 + if (ret) 1184 + return ret; 1185 + 1186 + return 0; 1187 + } 1188 + 1195 1189 static void pd692x0_of_put_managers(struct pd692x0_priv *priv, 1196 - struct pd692x0_manager *manager, 1197 - int nmanagers) 1190 + struct pd692x0_manager *manager) 1198 1191 { 1199 1192 int i, j; 1200 1193 1201 - for (i = 0; i < nmanagers; i++) { 1194 + for (i = 0; i < priv->nmanagers; i++) { 1202 1195 for (j = 0; j < manager[i].nports; j++) 1203 1196 of_node_put(manager[i].port_node[j]); 1204 1197 of_node_put(manager[i].node); ··· 1243 1198 } 1244 1199 } 1245 1200 1201 + static int 1202 + pd692x0_save_user_byte(struct pd692x0_priv *priv) 1203 + { 1204 + struct pd692x0_msg msg, buf; 1205 + 1206 + msg = pd692x0_msg_template_list[PD692X0_MSG_SET_USER_BYTE]; 1207 + return pd692x0_sendrecv_msg(priv, &msg, &buf); 1208 + } 1209 + 1246 1210 static int pd692x0_setup_pi_matrix(struct pse_controller_dev *pcdev) 1247 1211 { 1248 - struct pd692x0_manager *manager __free(kfree) = NULL; 1249 1212 struct pd692x0_priv *priv = to_pd692x0_priv(pcdev); 1250 - struct pd692x0_matrix port_matrix[PD692X0_MAX_PIS]; 1251 - int ret, nmanagers; 1252 - 1253 - /* Should we flash the port matrix */ 1254 - if (priv->fw_state != PD692X0_FW_OK && 1255 - priv->fw_state != PD692X0_FW_COMPLETE) 1256 - return 0; 1213 + struct pd692x0_matrix *port_matrix; 1214 + struct pd692x0_manager *manager; 1215 + int ret; 1257 1216 1258 1217 manager = kcalloc(PD692X0_MAX_MANAGERS, sizeof(*manager), GFP_KERNEL); 1259 1218 if (!manager) 1260 1219 return -ENOMEM; 1261 1220 1221 + port_matrix = devm_kcalloc(&priv->client->dev, PD692X0_MAX_PIS, 1222 + sizeof(*port_matrix), GFP_KERNEL); 1223 + if (!port_matrix) { 1224 + ret = -ENOMEM; 1225 + goto err_free_manager; 1226 + } 1227 + priv->port_matrix = port_matrix; 1228 + 1262 1229 ret = pd692x0_of_get_managers(priv, manager); 1263 1230 if (ret < 0) 1264 - return ret; 1231 + goto err_free_manager; 1265 1232 1266 - nmanagers = ret; 1267 - ret = pd692x0_register_managers_regulator(priv, manager, nmanagers); 1233 + ret = pd692x0_register_managers_regulator(priv, manager); 1268 1234 if (ret) 1269 1235 goto err_of_managers; 1270 1236 1271 - ret = pd692x0_configure_managers(priv, nmanagers); 1237 + ret = pd692x0_req_managers_pw_budget(priv); 1272 1238 if (ret) 1273 1239 goto err_of_managers; 1274 1240 1275 - ret = pd692x0_set_ports_matrix(priv, manager, nmanagers, port_matrix); 1241 + ret = pd692x0_set_ports_matrix(priv, manager); 1276 1242 if (ret) 1277 1243 goto err_managers_req_pw; 1278 1244 1279 - ret = pd692x0_write_ports_matrix(priv, port_matrix); 1280 - if (ret) 1281 - goto err_managers_req_pw; 1245 + /* Do not init the conf if it is already saved */ 1246 + if (!priv->cfg_saved) { 1247 + ret = pd692x0_hw_conf_init(priv); 1248 + if (ret) 1249 + goto err_managers_req_pw; 1282 1250 1283 - pd692x0_of_put_managers(priv, manager, nmanagers); 1251 + ret = pd692x0_save_user_byte(priv); 1252 + if (ret) 1253 + goto err_managers_req_pw; 1254 + } 1255 + 1256 + pd692x0_of_put_managers(priv, manager); 1257 + kfree(manager); 1284 1258 return 0; 1285 1259 1286 1260 err_managers_req_pw: 1287 1261 pd692x0_managers_free_pw_budget(priv); 1288 1262 err_of_managers: 1289 - pd692x0_of_put_managers(priv, manager, nmanagers); 1263 + pd692x0_of_put_managers(priv, manager); 1264 + err_free_manager: 1265 + kfree(manager); 1290 1266 return ret; 1291 1267 } 1292 1268 ··· 1710 1644 return FW_UPLOAD_ERR_FW_INVALID; 1711 1645 } 1712 1646 1713 - ret = pd692x0_setup_pi_matrix(&priv->pcdev); 1647 + ret = pd692x0_hw_conf_init(priv); 1714 1648 if (ret < 0) { 1715 1649 dev_err(&client->dev, "Error configuring ports matrix (%pe)\n", 1716 1650 ERR_PTR(ret)); ··· 1818 1752 priv->fw_state = PD692X0_FW_OK; 1819 1753 } 1820 1754 } 1755 + 1756 + if (buf.data[2] == PD692X0_USER_BYTE) 1757 + priv->cfg_saved = true; 1821 1758 1822 1759 priv->np = dev->of_node; 1823 1760 priv->pcdev.nr_lines = PD692X0_MAX_PIS;