diff options
Diffstat (limited to 'drivers/net/ethernet/sfc/mcdi.c')
-rw-r--r-- | drivers/net/ethernet/sfc/mcdi.c | 352 |
1 files changed, 233 insertions, 119 deletions
diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 1c8bf81bdc03..67b07de2c599 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c | |||
@@ -811,125 +811,6 @@ fail: | |||
811 | return rc; | 811 | return rc; |
812 | } | 812 | } |
813 | 813 | ||
814 | int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) | ||
815 | { | ||
816 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN); | ||
817 | int rc; | ||
818 | |||
819 | MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); | ||
820 | |||
821 | BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); | ||
822 | |||
823 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf), | ||
824 | NULL, 0, NULL); | ||
825 | if (rc) | ||
826 | goto fail; | ||
827 | |||
828 | return 0; | ||
829 | |||
830 | fail: | ||
831 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
832 | return rc; | ||
833 | } | ||
834 | |||
835 | int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, | ||
836 | loff_t offset, u8 *buffer, size_t length) | ||
837 | { | ||
838 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN); | ||
839 | MCDI_DECLARE_BUF(outbuf, | ||
840 | MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)); | ||
841 | size_t outlen; | ||
842 | int rc; | ||
843 | |||
844 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); | ||
845 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); | ||
846 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); | ||
847 | |||
848 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), | ||
849 | outbuf, sizeof(outbuf), &outlen); | ||
850 | if (rc) | ||
851 | goto fail; | ||
852 | |||
853 | memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); | ||
854 | return 0; | ||
855 | |||
856 | fail: | ||
857 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
858 | return rc; | ||
859 | } | ||
860 | |||
861 | int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, | ||
862 | loff_t offset, const u8 *buffer, size_t length) | ||
863 | { | ||
864 | MCDI_DECLARE_BUF(inbuf, | ||
865 | MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX)); | ||
866 | int rc; | ||
867 | |||
868 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); | ||
869 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); | ||
870 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); | ||
871 | memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); | ||
872 | |||
873 | BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); | ||
874 | |||
875 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, | ||
876 | ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4), | ||
877 | NULL, 0, NULL); | ||
878 | if (rc) | ||
879 | goto fail; | ||
880 | |||
881 | return 0; | ||
882 | |||
883 | fail: | ||
884 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
885 | return rc; | ||
886 | } | ||
887 | |||
888 | int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, | ||
889 | loff_t offset, size_t length) | ||
890 | { | ||
891 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN); | ||
892 | int rc; | ||
893 | |||
894 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type); | ||
895 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset); | ||
896 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length); | ||
897 | |||
898 | BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0); | ||
899 | |||
900 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf), | ||
901 | NULL, 0, NULL); | ||
902 | if (rc) | ||
903 | goto fail; | ||
904 | |||
905 | return 0; | ||
906 | |||
907 | fail: | ||
908 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
909 | return rc; | ||
910 | } | ||
911 | |||
912 | int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) | ||
913 | { | ||
914 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN); | ||
915 | int rc; | ||
916 | |||
917 | MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); | ||
918 | |||
919 | BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0); | ||
920 | |||
921 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), | ||
922 | NULL, 0, NULL); | ||
923 | if (rc) | ||
924 | goto fail; | ||
925 | |||
926 | return 0; | ||
927 | |||
928 | fail: | ||
929 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
930 | return rc; | ||
931 | } | ||
932 | |||
933 | static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type) | 814 | static int efx_mcdi_nvram_test(struct efx_nic *efx, unsigned int type) |
934 | { | 815 | { |
935 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN); | 816 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_TEST_IN_LEN); |
@@ -1272,3 +1153,236 @@ fail: | |||
1272 | return rc; | 1153 | return rc; |
1273 | } | 1154 | } |
1274 | 1155 | ||
1156 | #ifdef CONFIG_SFC_MTD | ||
1157 | |||
1158 | #define EFX_MCDI_NVRAM_LEN_MAX 128 | ||
1159 | |||
1160 | static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type) | ||
1161 | { | ||
1162 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_START_IN_LEN); | ||
1163 | int rc; | ||
1164 | |||
1165 | MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_START_IN_TYPE, type); | ||
1166 | |||
1167 | BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_START_OUT_LEN != 0); | ||
1168 | |||
1169 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf), | ||
1170 | NULL, 0, NULL); | ||
1171 | if (rc) | ||
1172 | goto fail; | ||
1173 | |||
1174 | return 0; | ||
1175 | |||
1176 | fail: | ||
1177 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
1178 | return rc; | ||
1179 | } | ||
1180 | |||
1181 | static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type, | ||
1182 | loff_t offset, u8 *buffer, size_t length) | ||
1183 | { | ||
1184 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_READ_IN_LEN); | ||
1185 | MCDI_DECLARE_BUF(outbuf, | ||
1186 | MC_CMD_NVRAM_READ_OUT_LEN(EFX_MCDI_NVRAM_LEN_MAX)); | ||
1187 | size_t outlen; | ||
1188 | int rc; | ||
1189 | |||
1190 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_TYPE, type); | ||
1191 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_OFFSET, offset); | ||
1192 | MCDI_SET_DWORD(inbuf, NVRAM_READ_IN_LENGTH, length); | ||
1193 | |||
1194 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf), | ||
1195 | outbuf, sizeof(outbuf), &outlen); | ||
1196 | if (rc) | ||
1197 | goto fail; | ||
1198 | |||
1199 | memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length); | ||
1200 | return 0; | ||
1201 | |||
1202 | fail: | ||
1203 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
1204 | return rc; | ||
1205 | } | ||
1206 | |||
1207 | static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type, | ||
1208 | loff_t offset, const u8 *buffer, size_t length) | ||
1209 | { | ||
1210 | MCDI_DECLARE_BUF(inbuf, | ||
1211 | MC_CMD_NVRAM_WRITE_IN_LEN(EFX_MCDI_NVRAM_LEN_MAX)); | ||
1212 | int rc; | ||
1213 | |||
1214 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_TYPE, type); | ||
1215 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_OFFSET, offset); | ||
1216 | MCDI_SET_DWORD(inbuf, NVRAM_WRITE_IN_LENGTH, length); | ||
1217 | memcpy(MCDI_PTR(inbuf, NVRAM_WRITE_IN_WRITE_BUFFER), buffer, length); | ||
1218 | |||
1219 | BUILD_BUG_ON(MC_CMD_NVRAM_WRITE_OUT_LEN != 0); | ||
1220 | |||
1221 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf, | ||
1222 | ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4), | ||
1223 | NULL, 0, NULL); | ||
1224 | if (rc) | ||
1225 | goto fail; | ||
1226 | |||
1227 | return 0; | ||
1228 | |||
1229 | fail: | ||
1230 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
1231 | return rc; | ||
1232 | } | ||
1233 | |||
1234 | static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type, | ||
1235 | loff_t offset, size_t length) | ||
1236 | { | ||
1237 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_ERASE_IN_LEN); | ||
1238 | int rc; | ||
1239 | |||
1240 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_TYPE, type); | ||
1241 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_OFFSET, offset); | ||
1242 | MCDI_SET_DWORD(inbuf, NVRAM_ERASE_IN_LENGTH, length); | ||
1243 | |||
1244 | BUILD_BUG_ON(MC_CMD_NVRAM_ERASE_OUT_LEN != 0); | ||
1245 | |||
1246 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf), | ||
1247 | NULL, 0, NULL); | ||
1248 | if (rc) | ||
1249 | goto fail; | ||
1250 | |||
1251 | return 0; | ||
1252 | |||
1253 | fail: | ||
1254 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
1255 | return rc; | ||
1256 | } | ||
1257 | |||
1258 | static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type) | ||
1259 | { | ||
1260 | MCDI_DECLARE_BUF(inbuf, MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN); | ||
1261 | int rc; | ||
1262 | |||
1263 | MCDI_SET_DWORD(inbuf, NVRAM_UPDATE_FINISH_IN_TYPE, type); | ||
1264 | |||
1265 | BUILD_BUG_ON(MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN != 0); | ||
1266 | |||
1267 | rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf), | ||
1268 | NULL, 0, NULL); | ||
1269 | if (rc) | ||
1270 | goto fail; | ||
1271 | |||
1272 | return 0; | ||
1273 | |||
1274 | fail: | ||
1275 | netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); | ||
1276 | return rc; | ||
1277 | } | ||
1278 | |||
1279 | int efx_mcdi_mtd_read(struct mtd_info *mtd, loff_t start, | ||
1280 | size_t len, size_t *retlen, u8 *buffer) | ||
1281 | { | ||
1282 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); | ||
1283 | struct efx_nic *efx = mtd->priv; | ||
1284 | loff_t offset = start; | ||
1285 | loff_t end = min_t(loff_t, start + len, mtd->size); | ||
1286 | size_t chunk; | ||
1287 | int rc = 0; | ||
1288 | |||
1289 | while (offset < end) { | ||
1290 | chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX); | ||
1291 | rc = efx_mcdi_nvram_read(efx, part->nvram_type, offset, | ||
1292 | buffer, chunk); | ||
1293 | if (rc) | ||
1294 | goto out; | ||
1295 | offset += chunk; | ||
1296 | buffer += chunk; | ||
1297 | } | ||
1298 | out: | ||
1299 | *retlen = offset - start; | ||
1300 | return rc; | ||
1301 | } | ||
1302 | |||
1303 | int efx_mcdi_mtd_erase(struct mtd_info *mtd, loff_t start, size_t len) | ||
1304 | { | ||
1305 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); | ||
1306 | struct efx_nic *efx = mtd->priv; | ||
1307 | loff_t offset = start & ~((loff_t)(mtd->erasesize - 1)); | ||
1308 | loff_t end = min_t(loff_t, start + len, mtd->size); | ||
1309 | size_t chunk = part->common.mtd.erasesize; | ||
1310 | int rc = 0; | ||
1311 | |||
1312 | if (!part->updating) { | ||
1313 | rc = efx_mcdi_nvram_update_start(efx, part->nvram_type); | ||
1314 | if (rc) | ||
1315 | goto out; | ||
1316 | part->updating = true; | ||
1317 | } | ||
1318 | |||
1319 | /* The MCDI interface can in fact do multiple erase blocks at once; | ||
1320 | * but erasing may be slow, so we make multiple calls here to avoid | ||
1321 | * tripping the MCDI RPC timeout. */ | ||
1322 | while (offset < end) { | ||
1323 | rc = efx_mcdi_nvram_erase(efx, part->nvram_type, offset, | ||
1324 | chunk); | ||
1325 | if (rc) | ||
1326 | goto out; | ||
1327 | offset += chunk; | ||
1328 | } | ||
1329 | out: | ||
1330 | return rc; | ||
1331 | } | ||
1332 | |||
1333 | int efx_mcdi_mtd_write(struct mtd_info *mtd, loff_t start, | ||
1334 | size_t len, size_t *retlen, const u8 *buffer) | ||
1335 | { | ||
1336 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); | ||
1337 | struct efx_nic *efx = mtd->priv; | ||
1338 | loff_t offset = start; | ||
1339 | loff_t end = min_t(loff_t, start + len, mtd->size); | ||
1340 | size_t chunk; | ||
1341 | int rc = 0; | ||
1342 | |||
1343 | if (!part->updating) { | ||
1344 | rc = efx_mcdi_nvram_update_start(efx, part->nvram_type); | ||
1345 | if (rc) | ||
1346 | goto out; | ||
1347 | part->updating = true; | ||
1348 | } | ||
1349 | |||
1350 | while (offset < end) { | ||
1351 | chunk = min_t(size_t, end - offset, EFX_MCDI_NVRAM_LEN_MAX); | ||
1352 | rc = efx_mcdi_nvram_write(efx, part->nvram_type, offset, | ||
1353 | buffer, chunk); | ||
1354 | if (rc) | ||
1355 | goto out; | ||
1356 | offset += chunk; | ||
1357 | buffer += chunk; | ||
1358 | } | ||
1359 | out: | ||
1360 | *retlen = offset - start; | ||
1361 | return rc; | ||
1362 | } | ||
1363 | |||
1364 | int efx_mcdi_mtd_sync(struct mtd_info *mtd) | ||
1365 | { | ||
1366 | struct efx_mcdi_mtd_partition *part = to_efx_mcdi_mtd_partition(mtd); | ||
1367 | struct efx_nic *efx = mtd->priv; | ||
1368 | int rc = 0; | ||
1369 | |||
1370 | if (part->updating) { | ||
1371 | part->updating = false; | ||
1372 | rc = efx_mcdi_nvram_update_finish(efx, part->nvram_type); | ||
1373 | } | ||
1374 | |||
1375 | return rc; | ||
1376 | } | ||
1377 | |||
1378 | void efx_mcdi_mtd_rename(struct efx_mtd_partition *part) | ||
1379 | { | ||
1380 | struct efx_mcdi_mtd_partition *mcdi_part = | ||
1381 | container_of(part, struct efx_mcdi_mtd_partition, common); | ||
1382 | struct efx_nic *efx = part->mtd.priv; | ||
1383 | |||
1384 | snprintf(part->name, sizeof(part->name), "%s %s:%02x", | ||
1385 | efx->name, part->type_name, mcdi_part->fw_subtype); | ||
1386 | } | ||
1387 | |||
1388 | #endif /* CONFIG_SFC_MTD */ | ||