diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2010-12-09 12:57:54 -0500 |
---|---|---|
committer | Borislav Petkov <borislav.petkov@amd.com> | 2011-03-17 09:46:13 -0400 |
commit | 229a7a11ac1afa84db2eac91b3fc38a0f5464696 (patch) | |
tree | 515508afed96c844be173c973ec3158a4363f544 /drivers/edac | |
parent | 11c75eadaf75fe6320325aa13dc135f26ad724b8 (diff) |
amd64_edac: Sanitize channel extraction
Cleanup and simplify f10_determine_channel(); make it more readable.
Also drop f10_map_intlv_en_to_shift() in favor of simply counting the
bits in F1x124[DramIntlvEn] which is equivalent.
There should be no functionality change resulting from this patch.
Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/amd64_edac.c | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 306850879f20..d9e951ce7167 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -1198,62 +1198,48 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt) | |||
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | /* | 1200 | /* |
1201 | * determine channel based on the interleaving mode: F10h BKDG, 2.8.9 Memory | 1201 | * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory |
1202 | * Interleaving Modes. | 1202 | * Interleaving Modes. |
1203 | */ | 1203 | */ |
1204 | static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, | 1204 | static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr, |
1205 | int hi_range_sel, u32 intlv_en) | 1205 | bool hi_range_sel, u8 intlv_en) |
1206 | { | 1206 | { |
1207 | u32 temp, dct_sel_high = (pvt->dct_sel_low >> 1) & 1; | 1207 | u32 dct_sel_high = (pvt->dct_sel_low >> 1) & 1; |
1208 | u8 cs; | ||
1209 | 1208 | ||
1210 | if (dct_ganging_enabled(pvt)) | 1209 | if (dct_ganging_enabled(pvt)) |
1211 | cs = 0; | 1210 | return 0; |
1212 | else if (hi_range_sel) | ||
1213 | cs = dct_sel_high; | ||
1214 | else if (dct_interleave_enabled(pvt)) { | ||
1215 | /* | ||
1216 | * see F2x110[DctSelIntLvAddr] - channel interleave mode | ||
1217 | */ | ||
1218 | if (dct_sel_interleave_addr(pvt) == 0) | ||
1219 | cs = sys_addr >> 6 & 1; | ||
1220 | else if ((dct_sel_interleave_addr(pvt) >> 1) & 1) { | ||
1221 | temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2; | ||
1222 | |||
1223 | if (dct_sel_interleave_addr(pvt) & 1) | ||
1224 | cs = (sys_addr >> 9 & 1) ^ temp; | ||
1225 | else | ||
1226 | cs = (sys_addr >> 6 & 1) ^ temp; | ||
1227 | } else if (intlv_en & 4) | ||
1228 | cs = sys_addr >> 15 & 1; | ||
1229 | else if (intlv_en & 2) | ||
1230 | cs = sys_addr >> 14 & 1; | ||
1231 | else if (intlv_en & 1) | ||
1232 | cs = sys_addr >> 13 & 1; | ||
1233 | else | ||
1234 | cs = sys_addr >> 12 & 1; | ||
1235 | } else if (dct_high_range_enabled(pvt) && !dct_ganging_enabled(pvt)) | ||
1236 | cs = ~dct_sel_high & 1; | ||
1237 | else | ||
1238 | cs = 0; | ||
1239 | 1211 | ||
1240 | return cs; | 1212 | if (hi_range_sel) |
1241 | } | 1213 | return dct_sel_high; |
1242 | 1214 | ||
1243 | static inline u32 f10_map_intlv_en_to_shift(u32 intlv_en) | 1215 | /* |
1244 | { | 1216 | * see F2x110[DctSelIntLvAddr] - channel interleave mode |
1245 | if (intlv_en == 1) | 1217 | */ |
1246 | return 1; | 1218 | if (dct_interleave_enabled(pvt)) { |
1247 | else if (intlv_en == 3) | 1219 | u8 intlv_addr = dct_sel_interleave_addr(pvt); |
1248 | return 2; | 1220 | |
1249 | else if (intlv_en == 7) | 1221 | /* return DCT select function: 0=DCT0, 1=DCT1 */ |
1250 | return 3; | 1222 | if (!intlv_addr) |
1223 | return sys_addr >> 6 & 1; | ||
1224 | |||
1225 | if (intlv_addr & 0x2) { | ||
1226 | u8 shift = intlv_addr & 0x1 ? 9 : 6; | ||
1227 | u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2; | ||
1228 | |||
1229 | return ((sys_addr >> shift) & 1) ^ temp; | ||
1230 | } | ||
1231 | |||
1232 | return (sys_addr >> (12 + hweight8(intlv_en))) & 1; | ||
1233 | } | ||
1234 | |||
1235 | if (dct_high_range_enabled(pvt)) | ||
1236 | return ~dct_sel_high & 1; | ||
1251 | 1237 | ||
1252 | return 0; | 1238 | return 0; |
1253 | } | 1239 | } |
1254 | 1240 | ||
1255 | /* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */ | 1241 | /* See F10h BKDG, 2.8.10.2 DctSelBaseOffset Programming */ |
1256 | static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel, | 1242 | static inline u64 f10_get_base_addr_offset(u64 sys_addr, bool hi_range_sel, |
1257 | u32 dct_sel_base_addr, | 1243 | u32 dct_sel_base_addr, |
1258 | u64 dct_sel_base_off, | 1244 | u64 dct_sel_base_off, |
1259 | u32 hole_valid, u64 hole_off, | 1245 | u32 hole_valid, u64 hole_off, |
@@ -1359,15 +1345,15 @@ static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct) | |||
1359 | static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, | 1345 | static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, |
1360 | u64 sys_addr, int *nid, int *chan_sel) | 1346 | u64 sys_addr, int *nid, int *chan_sel) |
1361 | { | 1347 | { |
1362 | int cs_found = -EINVAL, high_range = 0; | 1348 | int cs_found = -EINVAL; |
1363 | u64 chan_addr, dct_sel_base_off; | 1349 | u64 chan_addr, dct_sel_base_off; |
1364 | u64 hole_off; | 1350 | u64 hole_off; |
1365 | u32 hole_valid, tmp, dct_sel_base; | 1351 | u32 hole_valid, tmp, dct_sel_base; |
1366 | u32 intlv_shift; | ||
1367 | u8 channel; | 1352 | u8 channel; |
1353 | bool high_range = false; | ||
1368 | 1354 | ||
1369 | u8 node_id = dram_dst_node(pvt, range); | 1355 | u8 node_id = dram_dst_node(pvt, range); |
1370 | u32 intlv_en = dram_intlv_en(pvt, range); | 1356 | u8 intlv_en = dram_intlv_en(pvt, range); |
1371 | u32 intlv_sel = dram_intlv_sel(pvt, range); | 1357 | u32 intlv_sel = dram_intlv_sel(pvt, range); |
1372 | u64 dram_base = get_dram_base(pvt, range); | 1358 | u64 dram_base = get_dram_base(pvt, range); |
1373 | 1359 | ||
@@ -1398,7 +1384,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, | |||
1398 | if (dct_high_range_enabled(pvt) && | 1384 | if (dct_high_range_enabled(pvt) && |
1399 | !dct_ganging_enabled(pvt) && | 1385 | !dct_ganging_enabled(pvt) && |
1400 | ((sys_addr >> 27) >= (dct_sel_base >> 11))) | 1386 | ((sys_addr >> 27) >= (dct_sel_base >> 11))) |
1401 | high_range = 1; | 1387 | high_range = true; |
1402 | 1388 | ||
1403 | channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en); | 1389 | channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en); |
1404 | 1390 | ||
@@ -1406,12 +1392,10 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range, | |||
1406 | dct_sel_base_off, hole_valid, | 1392 | dct_sel_base_off, hole_valid, |
1407 | hole_off, dram_base); | 1393 | hole_off, dram_base); |
1408 | 1394 | ||
1409 | intlv_shift = f10_map_intlv_en_to_shift(intlv_en); | ||
1410 | |||
1411 | /* remove Node ID (in case of memory interleaving) */ | 1395 | /* remove Node ID (in case of memory interleaving) */ |
1412 | tmp = chan_addr & 0xFC0; | 1396 | tmp = chan_addr & 0xFC0; |
1413 | 1397 | ||
1414 | chan_addr = ((chan_addr >> intlv_shift) & 0xFFFFFFFFF000ULL) | tmp; | 1398 | chan_addr = ((chan_addr >> hweight8(intlv_en)) & 0xFFFFFFFFF000ULL) | tmp; |
1415 | 1399 | ||
1416 | /* remove channel interleave and hash */ | 1400 | /* remove channel interleave and hash */ |
1417 | if (dct_interleave_enabled(pvt) && | 1401 | if (dct_interleave_enabled(pvt) && |