Commit f2f10bd1 authored by Pu Wen's avatar Pu Wen
Browse files

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

hygon inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I7DX6V


CVE: NA

---------------------------

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: default avatarPu Wen <puwen@hygon.cn>
parent 55b01665
Loading
Loading
Loading
Loading
+38 −10
Original line number Diff line number Diff line
@@ -751,13 +751,21 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
	u8 cs_mask, cs_id = 0;
	bool hash_enabled = false;

	/* Read D18F0x1B4 (DramOffset), check if base 1 is used. */
	if (amd_df_indirect_read(nid, 0, 0x1B4, umc, &tmp))
	/* Read DramOffset, check if base 1 is used. */
	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;

	/* Remove HiAddrOffset from normalized address, if enabled: */
	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) {
			ret_addr -= hi_addr_offset;
@@ -776,6 +784,9 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
		goto out_err;
	}

	intlv_num_sockets = 0;
	if (hygon_f18h_m4h())
		intlv_num_sockets = (tmp >> 2) & 0x3;
	lgcy_mmio_hole_en = tmp & BIT(1);
	intlv_num_chan	  = (tmp >> 4) & 0xF;
	intlv_addr_sel	  = (tmp >> 8) & 0x7;
@@ -792,6 +803,7 @@ static 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))
		goto out_err;

	if (!hygon_f18h_m4h())
		intlv_num_sockets = (tmp >> 8) & 0x1;
	intlv_num_dies	  = (tmp >> 10) & 0x3;
	dram_limit_addr	  = ((tmp & GENMASK_ULL(31, 12)) << 16) | GENMASK_ULL(27, 0);
@@ -802,6 +814,10 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
	switch (intlv_num_chan) {
	case 0:	intlv_num_chan = 0; 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 5:	intlv_num_chan = 3; break;
	case 7:	intlv_num_chan = 4; break;
@@ -828,8 +844,9 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
	/* Add a bit if sockets are interleaved. */
	num_intlv_bits += intlv_num_sockets;

	/* Assert num_intlv_bits <= 4 */
	if (num_intlv_bits > 4) {
	/* Assert num_intlv_bits in the correct range. */
	if ((hygon_f18h_m4h() && num_intlv_bits > 7) ||
	    (!hygon_f18h_m4h() && num_intlv_bits > 4)) {
		pr_err("%s: Invalid interleave bits %d.\n",
			__func__, num_intlv_bits);
		goto out_err;
@@ -848,6 +865,9 @@ static 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))
			goto out_err;

		if (hygon_f18h_m4h())
			cs_fabric_id = (tmp >> 8) & 0x7FF;
		else
			cs_fabric_id = (tmp >> 8) & 0xFF;
		die_id_bit   = 0;

@@ -868,8 +888,13 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
		/* If interleaved over more than 1 die. */
		if (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_mask  = (tmp >> 8) & 0xFF;
			}

			cs_id |= ((cs_fabric_id & die_id_mask) >> die_id_shift) << die_id_bit;
		}
@@ -877,6 +902,9 @@ static int umc_normaddr_to_sysaddr(u64 norm_addr, u16 nid, u8 umc, u64 *sys_addr
		/* If interleaved over more than 1 socket. */
		if (intlv_num_sockets) {
			socket_id_shift	= (tmp >> 28) & 0xF;
			if (hygon_f18h_m4h())
				socket_id_mask	= (tmp >> 16) & 0x7FF;
			else
				socket_id_mask	= (tmp >> 16) & 0xFF;

			cs_id |= ((cs_fabric_id & socket_id_mask) >> socket_id_shift) << sock_id_bit;