xref: /linux-6.15/arch/x86/kernel/amd_node.c (revision 40a5f6ff)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * AMD Node helper functions and common defines
4  *
5  * Copyright (c) 2024, Advanced Micro Devices, Inc.
6  * All Rights Reserved.
7  *
8  * Author: Yazen Ghannam <[email protected]>
9  */
10 
11 #include <asm/amd_node.h>
12 
13 /*
14  * AMD Nodes are a physical collection of I/O devices within an SoC. There can be one
15  * or more nodes per package.
16  *
17  * The nodes are software-visible through PCI config space. All nodes are enumerated
18  * on segment 0 bus 0. The device (slot) numbers range from 0x18 to 0x1F (maximum 8
19  * nodes) with 0x18 corresponding to node 0, 0x19 to node 1, etc. Each node can be a
20  * multi-function device.
21  *
22  * On legacy systems, these node devices represent integrated Northbridge functionality.
23  * On Zen-based systems, these node devices represent Data Fabric functionality.
24  *
25  * See "Configuration Space Accesses" section in BKDGs or
26  * "Processor x86 Core" -> "Configuration Space" section in PPRs.
27  */
28 struct pci_dev *amd_node_get_func(u16 node, u8 func)
29 {
30 	if (node >= MAX_AMD_NUM_NODES)
31 		return NULL;
32 
33 	return pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(AMD_NODE0_PCI_SLOT + node, func));
34 }
35 
36 #define DF_BLK_INST_CNT		0x040
37 #define	DF_CFG_ADDR_CNTL_LEGACY	0x084
38 #define	DF_CFG_ADDR_CNTL_DF4	0xC04
39 
40 #define DF_MAJOR_REVISION	GENMASK(27, 24)
41 
42 static u16 get_cfg_addr_cntl_offset(struct pci_dev *df_f0)
43 {
44 	u32 reg;
45 
46 	/*
47 	 * Revision fields added for DF4 and later.
48 	 *
49 	 * Major revision of '0' is found pre-DF4. Field is Read-as-Zero.
50 	 */
51 	if (pci_read_config_dword(df_f0, DF_BLK_INST_CNT, &reg))
52 		return 0;
53 
54 	if (reg & DF_MAJOR_REVISION)
55 		return DF_CFG_ADDR_CNTL_DF4;
56 
57 	return DF_CFG_ADDR_CNTL_LEGACY;
58 }
59 
60 struct pci_dev *amd_node_get_root(u16 node)
61 {
62 	struct pci_dev *root;
63 	u16 cntl_off;
64 	u8 bus;
65 
66 	if (!cpu_feature_enabled(X86_FEATURE_ZEN))
67 		return NULL;
68 
69 	/*
70 	 * D18F0xXXX [Config Address Control] (DF::CfgAddressCntl)
71 	 * Bits [7:0] (SecBusNum) holds the bus number of the root device for
72 	 * this Data Fabric instance. The segment, device, and function will be 0.
73 	 */
74 	struct pci_dev *df_f0 __free(pci_dev_put) = amd_node_get_func(node, 0);
75 	if (!df_f0)
76 		return NULL;
77 
78 	cntl_off = get_cfg_addr_cntl_offset(df_f0);
79 	if (!cntl_off)
80 		return NULL;
81 
82 	if (pci_read_config_byte(df_f0, cntl_off, &bus))
83 		return NULL;
84 
85 	/* Grab the pointer for the actual root device instance. */
86 	root = pci_get_domain_bus_and_slot(0, bus, 0);
87 
88 	pci_dbg(root, "is root for AMD node %u\n", node);
89 	return root;
90 }
91