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, ®)) 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