EDAC/amd64: Adjust address translation for Hygon family 18h model 4h

Add Hygon family 18h model 4h processor support for DramOffset and
HiAddrOffset, and get the socket interleaving number from DramBase-
Address(D18F0x110).

Update intlv_num_chan and num_intlv_bits support for Hygon family 18h
model 4h processor.

Signed-off-by: Pu Wen <puwen@hygon.cn>
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
Reviewed-by: Bin Lai <robinlai@tencent.com>
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
Reviewed-by: caelli <caelli@tencent.com>
Signed-off-by: Jianping Liu <frankjpliu@tencent.com>
This commit is contained in:
Pu Wen 2023-06-08 12:39:07 +08:00 committed by Jianping Liu
parent 36d1aba7a1
commit 2c453f4b4e
1 changed files with 38 additions and 10 deletions

View File

@ -713,13 +713,21 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
u8 cs_mask, cs_id = 0; u8 cs_mask, cs_id = 0;
bool hash_enabled = false; bool hash_enabled = false;
/* Read D18F0x1B4 (DramOffset), check if base 1 is used. */ /* Read DramOffset, check if base 1 is used. */
if (amd_df_indirect_read(nid, 0, 0x1B4, umc, &tmp)) if (hygon_f18h_m4h() &&
amd_df_indirect_read(nid, 0, 0x214, umc, &tmp))
goto out_err;
else if (amd_df_indirect_read(nid, 0, 0x1B4, umc, &tmp))
goto out_err; goto out_err;
/* Remove HiAddrOffset from normalized address, if enabled: */ /* Remove HiAddrOffset from normalized address, if enabled: */
if (tmp & BIT(0)) { if (tmp & BIT(0)) {
u64 hi_addr_offset = (tmp & GENMASK_ULL(31, 20)) << 8; u64 hi_addr_offset;
if (hygon_f18h_m4h())
hi_addr_offset = (tmp & GENMASK_ULL(31, 18)) << 8;
else
hi_addr_offset = (tmp & GENMASK_ULL(31, 20)) << 8;
if (norm_addr >= hi_addr_offset) { if (norm_addr >= hi_addr_offset) {
ret_addr -= hi_addr_offset; ret_addr -= hi_addr_offset;
@ -738,6 +746,9 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
goto out_err; goto out_err;
} }
intlv_num_sockets = 0;
if (hygon_f18h_m4h())
intlv_num_sockets = (tmp >> 2) & 0x3;
lgcy_mmio_hole_en = tmp & BIT(1); lgcy_mmio_hole_en = tmp & BIT(1);
intlv_num_chan = (tmp >> 4) & 0xF; intlv_num_chan = (tmp >> 4) & 0xF;
intlv_addr_sel = (tmp >> 8) & 0x7; intlv_addr_sel = (tmp >> 8) & 0x7;
@ -754,6 +765,7 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
if (amd_df_indirect_read(nid, 0, 0x114 + (8 * base), umc, &tmp)) if (amd_df_indirect_read(nid, 0, 0x114 + (8 * base), umc, &tmp))
goto out_err; goto out_err;
if (!hygon_f18h_m4h())
intlv_num_sockets = (tmp >> 8) & 0x1; intlv_num_sockets = (tmp >> 8) & 0x1;
intlv_num_dies = (tmp >> 10) & 0x3; intlv_num_dies = (tmp >> 10) & 0x3;
dram_limit_addr = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0); dram_limit_addr = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0);
@ -764,6 +776,10 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
switch (intlv_num_chan) { switch (intlv_num_chan) {
case 0: intlv_num_chan = 0; break; case 0: intlv_num_chan = 0; break;
case 1: intlv_num_chan = 1; break; case 1: intlv_num_chan = 1; break;
case 2:
if (hygon_f18h_m4h())
intlv_num_chan = 2;
break;
case 3: intlv_num_chan = 2; break; case 3: intlv_num_chan = 2; break;
case 5: intlv_num_chan = 3; break; case 5: intlv_num_chan = 3; break;
case 7: intlv_num_chan = 4; break; case 7: intlv_num_chan = 4; break;
@ -790,8 +806,9 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
/* Add a bit if sockets are interleaved. */ /* Add a bit if sockets are interleaved. */
num_intlv_bits += intlv_num_sockets; num_intlv_bits += intlv_num_sockets;
/* Assert num_intlv_bits <= 4 */ /* Assert num_intlv_bits in the correct range. */
if (num_intlv_bits > 4) { if ((hygon_f18h_m4h() && num_intlv_bits > 7) ||
(!hygon_f18h_m4h() && num_intlv_bits > 4)) {
pr_err("%s: Invalid interleave bits %d.\n", pr_err("%s: Invalid interleave bits %d.\n",
__func__, num_intlv_bits); __func__, num_intlv_bits);
goto out_err; goto out_err;
@ -810,6 +827,9 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
if (amd_df_indirect_read(nid, 0, 0x50, umc, &tmp)) if (amd_df_indirect_read(nid, 0, 0x50, umc, &tmp))
goto out_err; goto out_err;
if (hygon_f18h_m4h())
cs_fabric_id = (tmp >> 8) & 0x7FF;
else
cs_fabric_id = (tmp >> 8) & 0xFF; cs_fabric_id = (tmp >> 8) & 0xFF;
die_id_bit = 0; die_id_bit = 0;
@ -830,8 +850,13 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
/* If interleaved over more than 1 die. */ /* If interleaved over more than 1 die. */
if (intlv_num_dies) { if (intlv_num_dies) {
sock_id_bit = die_id_bit + intlv_num_dies; sock_id_bit = die_id_bit + intlv_num_dies;
if (hygon_f18h_m4h()) {
die_id_shift = (tmp >> 12) & 0xF;
die_id_mask = tmp & 0x7FF;
} else {
die_id_shift = (tmp >> 24) & 0xF; die_id_shift = (tmp >> 24) & 0xF;
die_id_mask = (tmp >> 8) & 0xFF; die_id_mask = (tmp >> 8) & 0xFF;
}
cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << die_id_bit; cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << die_id_bit;
} }
@ -839,6 +864,9 @@ int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr)
/* If interleaved over more than 1 socket. */ /* If interleaved over more than 1 socket. */
if (intlv_num_sockets) { if (intlv_num_sockets) {
socket_id_shift = (tmp >> 28) & 0xF; socket_id_shift = (tmp >> 28) & 0xF;
if (hygon_f18h_m4h())
socket_id_mask = (tmp >> 16) & 0x7FF;
else
socket_id_mask = (tmp >> 16) & 0xFF; socket_id_mask = (tmp >> 16) & 0xFF;
cs_id |= ((cs_fabric_id & socket_id_mask) >> socket_id_shift) << sock_id_bit; cs_id |= ((cs_fabric_id & socket_id_mask) >> socket_id_shift) << sock_id_bit;