xref: /openbmc/linux/arch/x86/kernel/cpu/cacheinfo.c (revision 8ebc80a25f9d9bf7a8e368b266d5b740c485c362)
11d200c07SBorislav Petkov // SPDX-License-Identifier: GPL-2.0
21d200c07SBorislav Petkov /*
31d200c07SBorislav Petkov  *	Routines to identify caches on Intel CPU.
41d200c07SBorislav Petkov  *
51d200c07SBorislav Petkov  *	Changes:
61d200c07SBorislav Petkov  *	Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
71d200c07SBorislav Petkov  *	Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
81d200c07SBorislav Petkov  *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
91d200c07SBorislav Petkov  */
101d200c07SBorislav Petkov 
111d200c07SBorislav Petkov #include <linux/slab.h>
121d200c07SBorislav Petkov #include <linux/cacheinfo.h>
131d200c07SBorislav Petkov #include <linux/cpu.h>
1430f89e52SJuergen Gross #include <linux/cpuhotplug.h>
151d200c07SBorislav Petkov #include <linux/sched.h>
161d200c07SBorislav Petkov #include <linux/capability.h>
171d200c07SBorislav Petkov #include <linux/sysfs.h>
181d200c07SBorislav Petkov #include <linux/pci.h>
190b9a6a8bSJuergen Gross #include <linux/stop_machine.h>
201d200c07SBorislav Petkov 
211d200c07SBorislav Petkov #include <asm/cpufeature.h>
22ad3bc25aSBorislav Petkov #include <asm/cacheinfo.h>
231d200c07SBorislav Petkov #include <asm/amd_nb.h>
241d200c07SBorislav Petkov #include <asm/smp.h>
2523a63e36SJuergen Gross #include <asm/mtrr.h>
2623a63e36SJuergen Gross #include <asm/tlbflush.h>
271d200c07SBorislav Petkov 
28b5cf8707SThomas Gleixner #include "cpu.h"
29b5cf8707SThomas Gleixner 
301d200c07SBorislav Petkov #define LVL_1_INST	1
311d200c07SBorislav Petkov #define LVL_1_DATA	2
321d200c07SBorislav Petkov #define LVL_2		3
331d200c07SBorislav Petkov #define LVL_3		4
341d200c07SBorislav Petkov #define LVL_TRACE	5
351d200c07SBorislav Petkov 
36adbcaef8SSander Vanheule /* Shared last level cache maps */
37adbcaef8SSander Vanheule DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
38adbcaef8SSander Vanheule 
39adbcaef8SSander Vanheule /* Shared L2 cache maps */
40adbcaef8SSander Vanheule DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_l2c_shared_map);
41adbcaef8SSander Vanheule 
42a32226faSThomas Gleixner static cpumask_var_t cpu_cacheinfo_mask;
43a32226faSThomas Gleixner 
4445fa71f1SJuergen Gross /* Kernel controls MTRR and/or PAT MSRs. */
4545fa71f1SJuergen Gross unsigned int memory_caching_control __ro_after_init;
4645fa71f1SJuergen Gross 
471d200c07SBorislav Petkov struct _cache_table {
481d200c07SBorislav Petkov 	unsigned char descriptor;
491d200c07SBorislav Petkov 	char cache_type;
501d200c07SBorislav Petkov 	short size;
511d200c07SBorislav Petkov };
521d200c07SBorislav Petkov 
531d200c07SBorislav Petkov #define MB(x)	((x) * 1024)
541d200c07SBorislav Petkov 
551d200c07SBorislav Petkov /* All the cache descriptor types we care about (no TLB or
561d200c07SBorislav Petkov    trace cache entries) */
571d200c07SBorislav Petkov 
581d200c07SBorislav Petkov static const struct _cache_table cache_table[] =
591d200c07SBorislav Petkov {
601d200c07SBorislav Petkov 	{ 0x06, LVL_1_INST, 8 },	/* 4-way set assoc, 32 byte line size */
611d200c07SBorislav Petkov 	{ 0x08, LVL_1_INST, 16 },	/* 4-way set assoc, 32 byte line size */
621d200c07SBorislav Petkov 	{ 0x09, LVL_1_INST, 32 },	/* 4-way set assoc, 64 byte line size */
631d200c07SBorislav Petkov 	{ 0x0a, LVL_1_DATA, 8 },	/* 2 way set assoc, 32 byte line size */
641d200c07SBorislav Petkov 	{ 0x0c, LVL_1_DATA, 16 },	/* 4-way set assoc, 32 byte line size */
651d200c07SBorislav Petkov 	{ 0x0d, LVL_1_DATA, 16 },	/* 4-way set assoc, 64 byte line size */
661d200c07SBorislav Petkov 	{ 0x0e, LVL_1_DATA, 24 },	/* 6-way set assoc, 64 byte line size */
671d200c07SBorislav Petkov 	{ 0x21, LVL_2,      256 },	/* 8-way set assoc, 64 byte line size */
681d200c07SBorislav Petkov 	{ 0x22, LVL_3,      512 },	/* 4-way set assoc, sectored cache, 64 byte line size */
691d200c07SBorislav Petkov 	{ 0x23, LVL_3,      MB(1) },	/* 8-way set assoc, sectored cache, 64 byte line size */
701d200c07SBorislav Petkov 	{ 0x25, LVL_3,      MB(2) },	/* 8-way set assoc, sectored cache, 64 byte line size */
711d200c07SBorislav Petkov 	{ 0x29, LVL_3,      MB(4) },	/* 8-way set assoc, sectored cache, 64 byte line size */
721d200c07SBorislav Petkov 	{ 0x2c, LVL_1_DATA, 32 },	/* 8-way set assoc, 64 byte line size */
731d200c07SBorislav Petkov 	{ 0x30, LVL_1_INST, 32 },	/* 8-way set assoc, 64 byte line size */
741d200c07SBorislav Petkov 	{ 0x39, LVL_2,      128 },	/* 4-way set assoc, sectored cache, 64 byte line size */
751d200c07SBorislav Petkov 	{ 0x3a, LVL_2,      192 },	/* 6-way set assoc, sectored cache, 64 byte line size */
761d200c07SBorislav Petkov 	{ 0x3b, LVL_2,      128 },	/* 2-way set assoc, sectored cache, 64 byte line size */
771d200c07SBorislav Petkov 	{ 0x3c, LVL_2,      256 },	/* 4-way set assoc, sectored cache, 64 byte line size */
781d200c07SBorislav Petkov 	{ 0x3d, LVL_2,      384 },	/* 6-way set assoc, sectored cache, 64 byte line size */
791d200c07SBorislav Petkov 	{ 0x3e, LVL_2,      512 },	/* 4-way set assoc, sectored cache, 64 byte line size */
801d200c07SBorislav Petkov 	{ 0x3f, LVL_2,      256 },	/* 2-way set assoc, 64 byte line size */
811d200c07SBorislav Petkov 	{ 0x41, LVL_2,      128 },	/* 4-way set assoc, 32 byte line size */
821d200c07SBorislav Petkov 	{ 0x42, LVL_2,      256 },	/* 4-way set assoc, 32 byte line size */
831d200c07SBorislav Petkov 	{ 0x43, LVL_2,      512 },	/* 4-way set assoc, 32 byte line size */
841d200c07SBorislav Petkov 	{ 0x44, LVL_2,      MB(1) },	/* 4-way set assoc, 32 byte line size */
851d200c07SBorislav Petkov 	{ 0x45, LVL_2,      MB(2) },	/* 4-way set assoc, 32 byte line size */
861d200c07SBorislav Petkov 	{ 0x46, LVL_3,      MB(4) },	/* 4-way set assoc, 64 byte line size */
871d200c07SBorislav Petkov 	{ 0x47, LVL_3,      MB(8) },	/* 8-way set assoc, 64 byte line size */
881d200c07SBorislav Petkov 	{ 0x48, LVL_2,      MB(3) },	/* 12-way set assoc, 64 byte line size */
891d200c07SBorislav Petkov 	{ 0x49, LVL_3,      MB(4) },	/* 16-way set assoc, 64 byte line size */
901d200c07SBorislav Petkov 	{ 0x4a, LVL_3,      MB(6) },	/* 12-way set assoc, 64 byte line size */
911d200c07SBorislav Petkov 	{ 0x4b, LVL_3,      MB(8) },	/* 16-way set assoc, 64 byte line size */
921d200c07SBorislav Petkov 	{ 0x4c, LVL_3,      MB(12) },	/* 12-way set assoc, 64 byte line size */
931d200c07SBorislav Petkov 	{ 0x4d, LVL_3,      MB(16) },	/* 16-way set assoc, 64 byte line size */
941d200c07SBorislav Petkov 	{ 0x4e, LVL_2,      MB(6) },	/* 24-way set assoc, 64 byte line size */
951d200c07SBorislav Petkov 	{ 0x60, LVL_1_DATA, 16 },	/* 8-way set assoc, sectored cache, 64 byte line size */
961d200c07SBorislav Petkov 	{ 0x66, LVL_1_DATA, 8 },	/* 4-way set assoc, sectored cache, 64 byte line size */
971d200c07SBorislav Petkov 	{ 0x67, LVL_1_DATA, 16 },	/* 4-way set assoc, sectored cache, 64 byte line size */
981d200c07SBorislav Petkov 	{ 0x68, LVL_1_DATA, 32 },	/* 4-way set assoc, sectored cache, 64 byte line size */
991d200c07SBorislav Petkov 	{ 0x70, LVL_TRACE,  12 },	/* 8-way set assoc */
1001d200c07SBorislav Petkov 	{ 0x71, LVL_TRACE,  16 },	/* 8-way set assoc */
1011d200c07SBorislav Petkov 	{ 0x72, LVL_TRACE,  32 },	/* 8-way set assoc */
1021d200c07SBorislav Petkov 	{ 0x73, LVL_TRACE,  64 },	/* 8-way set assoc */
1031d200c07SBorislav Petkov 	{ 0x78, LVL_2,      MB(1) },	/* 4-way set assoc, 64 byte line size */
1041d200c07SBorislav Petkov 	{ 0x79, LVL_2,      128 },	/* 8-way set assoc, sectored cache, 64 byte line size */
1051d200c07SBorislav Petkov 	{ 0x7a, LVL_2,      256 },	/* 8-way set assoc, sectored cache, 64 byte line size */
1061d200c07SBorislav Petkov 	{ 0x7b, LVL_2,      512 },	/* 8-way set assoc, sectored cache, 64 byte line size */
1071d200c07SBorislav Petkov 	{ 0x7c, LVL_2,      MB(1) },	/* 8-way set assoc, sectored cache, 64 byte line size */
1081d200c07SBorislav Petkov 	{ 0x7d, LVL_2,      MB(2) },	/* 8-way set assoc, 64 byte line size */
1091d200c07SBorislav Petkov 	{ 0x7f, LVL_2,      512 },	/* 2-way set assoc, 64 byte line size */
1101d200c07SBorislav Petkov 	{ 0x80, LVL_2,      512 },	/* 8-way set assoc, 64 byte line size */
1111d200c07SBorislav Petkov 	{ 0x82, LVL_2,      256 },	/* 8-way set assoc, 32 byte line size */
1121d200c07SBorislav Petkov 	{ 0x83, LVL_2,      512 },	/* 8-way set assoc, 32 byte line size */
1131d200c07SBorislav Petkov 	{ 0x84, LVL_2,      MB(1) },	/* 8-way set assoc, 32 byte line size */
1141d200c07SBorislav Petkov 	{ 0x85, LVL_2,      MB(2) },	/* 8-way set assoc, 32 byte line size */
1151d200c07SBorislav Petkov 	{ 0x86, LVL_2,      512 },	/* 4-way set assoc, 64 byte line size */
1161d200c07SBorislav Petkov 	{ 0x87, LVL_2,      MB(1) },	/* 8-way set assoc, 64 byte line size */
1171d200c07SBorislav Petkov 	{ 0xd0, LVL_3,      512 },	/* 4-way set assoc, 64 byte line size */
1181d200c07SBorislav Petkov 	{ 0xd1, LVL_3,      MB(1) },	/* 4-way set assoc, 64 byte line size */
1191d200c07SBorislav Petkov 	{ 0xd2, LVL_3,      MB(2) },	/* 4-way set assoc, 64 byte line size */
1201d200c07SBorislav Petkov 	{ 0xd6, LVL_3,      MB(1) },	/* 8-way set assoc, 64 byte line size */
1211d200c07SBorislav Petkov 	{ 0xd7, LVL_3,      MB(2) },	/* 8-way set assoc, 64 byte line size */
1221d200c07SBorislav Petkov 	{ 0xd8, LVL_3,      MB(4) },	/* 12-way set assoc, 64 byte line size */
1231d200c07SBorislav Petkov 	{ 0xdc, LVL_3,      MB(2) },	/* 12-way set assoc, 64 byte line size */
1241d200c07SBorislav Petkov 	{ 0xdd, LVL_3,      MB(4) },	/* 12-way set assoc, 64 byte line size */
1251d200c07SBorislav Petkov 	{ 0xde, LVL_3,      MB(8) },	/* 12-way set assoc, 64 byte line size */
1261d200c07SBorislav Petkov 	{ 0xe2, LVL_3,      MB(2) },	/* 16-way set assoc, 64 byte line size */
1271d200c07SBorislav Petkov 	{ 0xe3, LVL_3,      MB(4) },	/* 16-way set assoc, 64 byte line size */
1281d200c07SBorislav Petkov 	{ 0xe4, LVL_3,      MB(8) },	/* 16-way set assoc, 64 byte line size */
1291d200c07SBorislav Petkov 	{ 0xea, LVL_3,      MB(12) },	/* 24-way set assoc, 64 byte line size */
1301d200c07SBorislav Petkov 	{ 0xeb, LVL_3,      MB(18) },	/* 24-way set assoc, 64 byte line size */
1311d200c07SBorislav Petkov 	{ 0xec, LVL_3,      MB(24) },	/* 24-way set assoc, 64 byte line size */
1321d200c07SBorislav Petkov 	{ 0x00, 0, 0}
1331d200c07SBorislav Petkov };
1341d200c07SBorislav Petkov 
1351d200c07SBorislav Petkov 
1361d200c07SBorislav Petkov enum _cache_type {
1371d200c07SBorislav Petkov 	CTYPE_NULL = 0,
1381d200c07SBorislav Petkov 	CTYPE_DATA = 1,
1391d200c07SBorislav Petkov 	CTYPE_INST = 2,
1401d200c07SBorislav Petkov 	CTYPE_UNIFIED = 3
1411d200c07SBorislav Petkov };
1421d200c07SBorislav Petkov 
1431d200c07SBorislav Petkov union _cpuid4_leaf_eax {
1441d200c07SBorislav Petkov 	struct {
1451d200c07SBorislav Petkov 		enum _cache_type	type:5;
1461d200c07SBorislav Petkov 		unsigned int		level:3;
1471d200c07SBorislav Petkov 		unsigned int		is_self_initializing:1;
1481d200c07SBorislav Petkov 		unsigned int		is_fully_associative:1;
1491d200c07SBorislav Petkov 		unsigned int		reserved:4;
1501d200c07SBorislav Petkov 		unsigned int		num_threads_sharing:12;
1511d200c07SBorislav Petkov 		unsigned int		num_cores_on_die:6;
1521d200c07SBorislav Petkov 	} split;
1531d200c07SBorislav Petkov 	u32 full;
1541d200c07SBorislav Petkov };
1551d200c07SBorislav Petkov 
1561d200c07SBorislav Petkov union _cpuid4_leaf_ebx {
1571d200c07SBorislav Petkov 	struct {
1581d200c07SBorislav Petkov 		unsigned int		coherency_line_size:12;
1591d200c07SBorislav Petkov 		unsigned int		physical_line_partition:10;
1601d200c07SBorislav Petkov 		unsigned int		ways_of_associativity:10;
1611d200c07SBorislav Petkov 	} split;
1621d200c07SBorislav Petkov 	u32 full;
1631d200c07SBorislav Petkov };
1641d200c07SBorislav Petkov 
1651d200c07SBorislav Petkov union _cpuid4_leaf_ecx {
1661d200c07SBorislav Petkov 	struct {
1671d200c07SBorislav Petkov 		unsigned int		number_of_sets:32;
1681d200c07SBorislav Petkov 	} split;
1691d200c07SBorislav Petkov 	u32 full;
1701d200c07SBorislav Petkov };
1711d200c07SBorislav Petkov 
1721d200c07SBorislav Petkov struct _cpuid4_info_regs {
1731d200c07SBorislav Petkov 	union _cpuid4_leaf_eax eax;
1741d200c07SBorislav Petkov 	union _cpuid4_leaf_ebx ebx;
1751d200c07SBorislav Petkov 	union _cpuid4_leaf_ecx ecx;
1761d200c07SBorislav Petkov 	unsigned int id;
1771d200c07SBorislav Petkov 	unsigned long size;
1781d200c07SBorislav Petkov 	struct amd_northbridge *nb;
1791d200c07SBorislav Petkov };
1801d200c07SBorislav Petkov 
1811d200c07SBorislav Petkov static unsigned short num_cache_leaves;
1821d200c07SBorislav Petkov 
1831d200c07SBorislav Petkov /* AMD doesn't have CPUID4. Emulate it here to report the same
1841d200c07SBorislav Petkov    information to the user.  This makes some assumptions about the machine:
1851d200c07SBorislav Petkov    L2 not shared, no SMT etc. that is currently true on AMD CPUs.
1861d200c07SBorislav Petkov 
1871d200c07SBorislav Petkov    In theory the TLBs could be reported as fake type (they are in "dummy").
1881d200c07SBorislav Petkov    Maybe later */
1891d200c07SBorislav Petkov union l1_cache {
1901d200c07SBorislav Petkov 	struct {
1911d200c07SBorislav Petkov 		unsigned line_size:8;
1921d200c07SBorislav Petkov 		unsigned lines_per_tag:8;
1931d200c07SBorislav Petkov 		unsigned assoc:8;
1941d200c07SBorislav Petkov 		unsigned size_in_kb:8;
1951d200c07SBorislav Petkov 	};
1961d200c07SBorislav Petkov 	unsigned val;
1971d200c07SBorislav Petkov };
1981d200c07SBorislav Petkov 
1991d200c07SBorislav Petkov union l2_cache {
2001d200c07SBorislav Petkov 	struct {
2011d200c07SBorislav Petkov 		unsigned line_size:8;
2021d200c07SBorislav Petkov 		unsigned lines_per_tag:4;
2031d200c07SBorislav Petkov 		unsigned assoc:4;
2041d200c07SBorislav Petkov 		unsigned size_in_kb:16;
2051d200c07SBorislav Petkov 	};
2061d200c07SBorislav Petkov 	unsigned val;
2071d200c07SBorislav Petkov };
2081d200c07SBorislav Petkov 
2091d200c07SBorislav Petkov union l3_cache {
2101d200c07SBorislav Petkov 	struct {
2111d200c07SBorislav Petkov 		unsigned line_size:8;
2121d200c07SBorislav Petkov 		unsigned lines_per_tag:4;
2131d200c07SBorislav Petkov 		unsigned assoc:4;
2141d200c07SBorislav Petkov 		unsigned res:2;
2151d200c07SBorislav Petkov 		unsigned size_encoded:14;
2161d200c07SBorislav Petkov 	};
2171d200c07SBorislav Petkov 	unsigned val;
2181d200c07SBorislav Petkov };
2191d200c07SBorislav Petkov 
2201d200c07SBorislav Petkov static const unsigned short assocs[] = {
2211d200c07SBorislav Petkov 	[1] = 1,
2221d200c07SBorislav Petkov 	[2] = 2,
2231d200c07SBorislav Petkov 	[4] = 4,
2241d200c07SBorislav Petkov 	[6] = 8,
2251d200c07SBorislav Petkov 	[8] = 16,
2261d200c07SBorislav Petkov 	[0xa] = 32,
2271d200c07SBorislav Petkov 	[0xb] = 48,
2281d200c07SBorislav Petkov 	[0xc] = 64,
2291d200c07SBorislav Petkov 	[0xd] = 96,
2301d200c07SBorislav Petkov 	[0xe] = 128,
2311d200c07SBorislav Petkov 	[0xf] = 0xffff /* fully associative - no way to show this currently */
2321d200c07SBorislav Petkov };
2331d200c07SBorislav Petkov 
2341d200c07SBorislav Petkov static const unsigned char levels[] = { 1, 1, 2, 3 };
2351d200c07SBorislav Petkov static const unsigned char types[] = { 1, 2, 3, 3 };
2361d200c07SBorislav Petkov 
2371d200c07SBorislav Petkov static const enum cache_type cache_type_map[] = {
2381d200c07SBorislav Petkov 	[CTYPE_NULL] = CACHE_TYPE_NOCACHE,
2391d200c07SBorislav Petkov 	[CTYPE_DATA] = CACHE_TYPE_DATA,
2401d200c07SBorislav Petkov 	[CTYPE_INST] = CACHE_TYPE_INST,
2411d200c07SBorislav Petkov 	[CTYPE_UNIFIED] = CACHE_TYPE_UNIFIED,
2421d200c07SBorislav Petkov };
2431d200c07SBorislav Petkov 
2441d200c07SBorislav Petkov static void
amd_cpuid4(int leaf,union _cpuid4_leaf_eax * eax,union _cpuid4_leaf_ebx * ebx,union _cpuid4_leaf_ecx * ecx)2451d200c07SBorislav Petkov amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
2461d200c07SBorislav Petkov 		     union _cpuid4_leaf_ebx *ebx,
2471d200c07SBorislav Petkov 		     union _cpuid4_leaf_ecx *ecx)
2481d200c07SBorislav Petkov {
2491d200c07SBorislav Petkov 	unsigned dummy;
2501d200c07SBorislav Petkov 	unsigned line_size, lines_per_tag, assoc, size_in_kb;
2511d200c07SBorislav Petkov 	union l1_cache l1i, l1d;
2521d200c07SBorislav Petkov 	union l2_cache l2;
2531d200c07SBorislav Petkov 	union l3_cache l3;
2541d200c07SBorislav Petkov 	union l1_cache *l1 = &l1d;
2551d200c07SBorislav Petkov 
2561d200c07SBorislav Petkov 	eax->full = 0;
2571d200c07SBorislav Petkov 	ebx->full = 0;
2581d200c07SBorislav Petkov 	ecx->full = 0;
2591d200c07SBorislav Petkov 
2601d200c07SBorislav Petkov 	cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
2611d200c07SBorislav Petkov 	cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
2621d200c07SBorislav Petkov 
2631d200c07SBorislav Petkov 	switch (leaf) {
2641d200c07SBorislav Petkov 	case 1:
2651d200c07SBorislav Petkov 		l1 = &l1i;
266df561f66SGustavo A. R. Silva 		fallthrough;
2671d200c07SBorislav Petkov 	case 0:
2681d200c07SBorislav Petkov 		if (!l1->val)
2691d200c07SBorislav Petkov 			return;
2701d200c07SBorislav Petkov 		assoc = assocs[l1->assoc];
2711d200c07SBorislav Petkov 		line_size = l1->line_size;
2721d200c07SBorislav Petkov 		lines_per_tag = l1->lines_per_tag;
2731d200c07SBorislav Petkov 		size_in_kb = l1->size_in_kb;
2741d200c07SBorislav Petkov 		break;
2751d200c07SBorislav Petkov 	case 2:
2761d200c07SBorislav Petkov 		if (!l2.val)
2771d200c07SBorislav Petkov 			return;
2781d200c07SBorislav Petkov 		assoc = assocs[l2.assoc];
2791d200c07SBorislav Petkov 		line_size = l2.line_size;
2801d200c07SBorislav Petkov 		lines_per_tag = l2.lines_per_tag;
2811d200c07SBorislav Petkov 		/* cpu_data has errata corrections for K7 applied */
2821d200c07SBorislav Petkov 		size_in_kb = __this_cpu_read(cpu_info.x86_cache_size);
2831d200c07SBorislav Petkov 		break;
2841d200c07SBorislav Petkov 	case 3:
2851d200c07SBorislav Petkov 		if (!l3.val)
2861d200c07SBorislav Petkov 			return;
2871d200c07SBorislav Petkov 		assoc = assocs[l3.assoc];
2881d200c07SBorislav Petkov 		line_size = l3.line_size;
2891d200c07SBorislav Petkov 		lines_per_tag = l3.lines_per_tag;
2901d200c07SBorislav Petkov 		size_in_kb = l3.size_encoded * 512;
2911d200c07SBorislav Petkov 		if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {
2921d200c07SBorislav Petkov 			size_in_kb = size_in_kb >> 1;
2931d200c07SBorislav Petkov 			assoc = assoc >> 1;
2941d200c07SBorislav Petkov 		}
2951d200c07SBorislav Petkov 		break;
2961d200c07SBorislav Petkov 	default:
2971d200c07SBorislav Petkov 		return;
2981d200c07SBorislav Petkov 	}
2991d200c07SBorislav Petkov 
3001d200c07SBorislav Petkov 	eax->split.is_self_initializing = 1;
3011d200c07SBorislav Petkov 	eax->split.type = types[leaf];
3021d200c07SBorislav Petkov 	eax->split.level = levels[leaf];
3031d200c07SBorislav Petkov 	eax->split.num_threads_sharing = 0;
3041d200c07SBorislav Petkov 	eax->split.num_cores_on_die = __this_cpu_read(cpu_info.x86_max_cores) - 1;
3051d200c07SBorislav Petkov 
3061d200c07SBorislav Petkov 
3071d200c07SBorislav Petkov 	if (assoc == 0xffff)
3081d200c07SBorislav Petkov 		eax->split.is_fully_associative = 1;
3091d200c07SBorislav Petkov 	ebx->split.coherency_line_size = line_size - 1;
3101d200c07SBorislav Petkov 	ebx->split.ways_of_associativity = assoc - 1;
3111d200c07SBorislav Petkov 	ebx->split.physical_line_partition = lines_per_tag - 1;
3121d200c07SBorislav Petkov 	ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
3131d200c07SBorislav Petkov 		(ebx->split.ways_of_associativity + 1) - 1;
3141d200c07SBorislav Petkov }
3151d200c07SBorislav Petkov 
3161d200c07SBorislav Petkov #if defined(CONFIG_AMD_NB) && defined(CONFIG_SYSFS)
3171d200c07SBorislav Petkov 
3181d200c07SBorislav Petkov /*
3191d200c07SBorislav Petkov  * L3 cache descriptors
3201d200c07SBorislav Petkov  */
amd_calc_l3_indices(struct amd_northbridge * nb)3211d200c07SBorislav Petkov static void amd_calc_l3_indices(struct amd_northbridge *nb)
3221d200c07SBorislav Petkov {
3231d200c07SBorislav Petkov 	struct amd_l3_cache *l3 = &nb->l3_cache;
3241d200c07SBorislav Petkov 	unsigned int sc0, sc1, sc2, sc3;
3251d200c07SBorislav Petkov 	u32 val = 0;
3261d200c07SBorislav Petkov 
3271d200c07SBorislav Petkov 	pci_read_config_dword(nb->misc, 0x1C4, &val);
3281d200c07SBorislav Petkov 
3291d200c07SBorislav Petkov 	/* calculate subcache sizes */
3301d200c07SBorislav Petkov 	l3->subcaches[0] = sc0 = !(val & BIT(0));
3311d200c07SBorislav Petkov 	l3->subcaches[1] = sc1 = !(val & BIT(4));
3321d200c07SBorislav Petkov 
3331d200c07SBorislav Petkov 	if (boot_cpu_data.x86 == 0x15) {
3341d200c07SBorislav Petkov 		l3->subcaches[0] = sc0 += !(val & BIT(1));
3351d200c07SBorislav Petkov 		l3->subcaches[1] = sc1 += !(val & BIT(5));
3361d200c07SBorislav Petkov 	}
3371d200c07SBorislav Petkov 
3381d200c07SBorislav Petkov 	l3->subcaches[2] = sc2 = !(val & BIT(8))  + !(val & BIT(9));
3391d200c07SBorislav Petkov 	l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
3401d200c07SBorislav Petkov 
3411d200c07SBorislav Petkov 	l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
3421d200c07SBorislav Petkov }
3431d200c07SBorislav Petkov 
3441d200c07SBorislav Petkov /*
3451d200c07SBorislav Petkov  * check whether a slot used for disabling an L3 index is occupied.
3461d200c07SBorislav Petkov  * @l3: L3 cache descriptor
3471d200c07SBorislav Petkov  * @slot: slot number (0..1)
3481d200c07SBorislav Petkov  *
3491d200c07SBorislav Petkov  * @returns: the disabled index if used or negative value if slot free.
3501d200c07SBorislav Petkov  */
amd_get_l3_disable_slot(struct amd_northbridge * nb,unsigned slot)3511d200c07SBorislav Petkov static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot)
3521d200c07SBorislav Petkov {
3531d200c07SBorislav Petkov 	unsigned int reg = 0;
3541d200c07SBorislav Petkov 
3551d200c07SBorislav Petkov 	pci_read_config_dword(nb->misc, 0x1BC + slot * 4, &reg);
3561d200c07SBorislav Petkov 
3571d200c07SBorislav Petkov 	/* check whether this slot is activated already */
3581d200c07SBorislav Petkov 	if (reg & (3UL << 30))
3591d200c07SBorislav Petkov 		return reg & 0xfff;
3601d200c07SBorislav Petkov 
3611d200c07SBorislav Petkov 	return -1;
3621d200c07SBorislav Petkov }
3631d200c07SBorislav Petkov 
show_cache_disable(struct cacheinfo * this_leaf,char * buf,unsigned int slot)3641d200c07SBorislav Petkov static ssize_t show_cache_disable(struct cacheinfo *this_leaf, char *buf,
3651d200c07SBorislav Petkov 				  unsigned int slot)
3661d200c07SBorislav Petkov {
3671d200c07SBorislav Petkov 	int index;
3681d200c07SBorislav Petkov 	struct amd_northbridge *nb = this_leaf->priv;
3691d200c07SBorislav Petkov 
3701d200c07SBorislav Petkov 	index = amd_get_l3_disable_slot(nb, slot);
3711d200c07SBorislav Petkov 	if (index >= 0)
3721d200c07SBorislav Petkov 		return sprintf(buf, "%d\n", index);
3731d200c07SBorislav Petkov 
3741d200c07SBorislav Petkov 	return sprintf(buf, "FREE\n");
3751d200c07SBorislav Petkov }
3761d200c07SBorislav Petkov 
3771d200c07SBorislav Petkov #define SHOW_CACHE_DISABLE(slot)					\
3781d200c07SBorislav Petkov static ssize_t								\
3791d200c07SBorislav Petkov cache_disable_##slot##_show(struct device *dev,				\
3801d200c07SBorislav Petkov 			    struct device_attribute *attr, char *buf)	\
3811d200c07SBorislav Petkov {									\
3821d200c07SBorislav Petkov 	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
3831d200c07SBorislav Petkov 	return show_cache_disable(this_leaf, buf, slot);		\
3841d200c07SBorislav Petkov }
3851d200c07SBorislav Petkov SHOW_CACHE_DISABLE(0)
3861d200c07SBorislav Petkov SHOW_CACHE_DISABLE(1)
3871d200c07SBorislav Petkov 
amd_l3_disable_index(struct amd_northbridge * nb,int cpu,unsigned slot,unsigned long idx)3881d200c07SBorislav Petkov static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu,
3891d200c07SBorislav Petkov 				 unsigned slot, unsigned long idx)
3901d200c07SBorislav Petkov {
3911d200c07SBorislav Petkov 	int i;
3921d200c07SBorislav Petkov 
3931d200c07SBorislav Petkov 	idx |= BIT(30);
3941d200c07SBorislav Petkov 
3951d200c07SBorislav Petkov 	/*
3961d200c07SBorislav Petkov 	 *  disable index in all 4 subcaches
3971d200c07SBorislav Petkov 	 */
3981d200c07SBorislav Petkov 	for (i = 0; i < 4; i++) {
3991d200c07SBorislav Petkov 		u32 reg = idx | (i << 20);
4001d200c07SBorislav Petkov 
4011d200c07SBorislav Petkov 		if (!nb->l3_cache.subcaches[i])
4021d200c07SBorislav Petkov 			continue;
4031d200c07SBorislav Petkov 
4041d200c07SBorislav Petkov 		pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
4051d200c07SBorislav Petkov 
4061d200c07SBorislav Petkov 		/*
4071d200c07SBorislav Petkov 		 * We need to WBINVD on a core on the node containing the L3
4081d200c07SBorislav Petkov 		 * cache which indices we disable therefore a simple wbinvd()
4091d200c07SBorislav Petkov 		 * is not sufficient.
4101d200c07SBorislav Petkov 		 */
4111d200c07SBorislav Petkov 		wbinvd_on_cpu(cpu);
4121d200c07SBorislav Petkov 
4131d200c07SBorislav Petkov 		reg |= BIT(31);
4141d200c07SBorislav Petkov 		pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg);
4151d200c07SBorislav Petkov 	}
4161d200c07SBorislav Petkov }
4171d200c07SBorislav Petkov 
4181d200c07SBorislav Petkov /*
4191d200c07SBorislav Petkov  * disable a L3 cache index by using a disable-slot
4201d200c07SBorislav Petkov  *
4211d200c07SBorislav Petkov  * @l3:    L3 cache descriptor
4221d200c07SBorislav Petkov  * @cpu:   A CPU on the node containing the L3 cache
4231d200c07SBorislav Petkov  * @slot:  slot number (0..1)
4241d200c07SBorislav Petkov  * @index: index to disable
4251d200c07SBorislav Petkov  *
4261d200c07SBorislav Petkov  * @return: 0 on success, error status on failure
4271d200c07SBorislav Petkov  */
amd_set_l3_disable_slot(struct amd_northbridge * nb,int cpu,unsigned slot,unsigned long index)4281d200c07SBorislav Petkov static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu,
4291d200c07SBorislav Petkov 			    unsigned slot, unsigned long index)
4301d200c07SBorislav Petkov {
4311d200c07SBorislav Petkov 	int ret = 0;
4321d200c07SBorislav Petkov 
4331d200c07SBorislav Petkov 	/*  check if @slot is already used or the index is already disabled */
4341d200c07SBorislav Petkov 	ret = amd_get_l3_disable_slot(nb, slot);
4351d200c07SBorislav Petkov 	if (ret >= 0)
4361d200c07SBorislav Petkov 		return -EEXIST;
4371d200c07SBorislav Petkov 
4381d200c07SBorislav Petkov 	if (index > nb->l3_cache.indices)
4391d200c07SBorislav Petkov 		return -EINVAL;
4401d200c07SBorislav Petkov 
4411d200c07SBorislav Petkov 	/* check whether the other slot has disabled the same index already */
4421d200c07SBorislav Petkov 	if (index == amd_get_l3_disable_slot(nb, !slot))
4431d200c07SBorislav Petkov 		return -EEXIST;
4441d200c07SBorislav Petkov 
4451d200c07SBorislav Petkov 	amd_l3_disable_index(nb, cpu, slot, index);
4461d200c07SBorislav Petkov 
4471d200c07SBorislav Petkov 	return 0;
4481d200c07SBorislav Petkov }
4491d200c07SBorislav Petkov 
store_cache_disable(struct cacheinfo * this_leaf,const char * buf,size_t count,unsigned int slot)4501d200c07SBorislav Petkov static ssize_t store_cache_disable(struct cacheinfo *this_leaf,
4511d200c07SBorislav Petkov 				   const char *buf, size_t count,
4521d200c07SBorislav Petkov 				   unsigned int slot)
4531d200c07SBorislav Petkov {
4541d200c07SBorislav Petkov 	unsigned long val = 0;
4551d200c07SBorislav Petkov 	int cpu, err = 0;
4561d200c07SBorislav Petkov 	struct amd_northbridge *nb = this_leaf->priv;
4571d200c07SBorislav Petkov 
4581d200c07SBorislav Petkov 	if (!capable(CAP_SYS_ADMIN))
4591d200c07SBorislav Petkov 		return -EPERM;
4601d200c07SBorislav Petkov 
4611d200c07SBorislav Petkov 	cpu = cpumask_first(&this_leaf->shared_cpu_map);
4621d200c07SBorislav Petkov 
4631d200c07SBorislav Petkov 	if (kstrtoul(buf, 10, &val) < 0)
4641d200c07SBorislav Petkov 		return -EINVAL;
4651d200c07SBorislav Petkov 
4661d200c07SBorislav Petkov 	err = amd_set_l3_disable_slot(nb, cpu, slot, val);
4671d200c07SBorislav Petkov 	if (err) {
4681d200c07SBorislav Petkov 		if (err == -EEXIST)
4691d200c07SBorislav Petkov 			pr_warn("L3 slot %d in use/index already disabled!\n",
4701d200c07SBorislav Petkov 				   slot);
4711d200c07SBorislav Petkov 		return err;
4721d200c07SBorislav Petkov 	}
4731d200c07SBorislav Petkov 	return count;
4741d200c07SBorislav Petkov }
4751d200c07SBorislav Petkov 
4761d200c07SBorislav Petkov #define STORE_CACHE_DISABLE(slot)					\
4771d200c07SBorislav Petkov static ssize_t								\
4781d200c07SBorislav Petkov cache_disable_##slot##_store(struct device *dev,			\
4791d200c07SBorislav Petkov 			     struct device_attribute *attr,		\
4801d200c07SBorislav Petkov 			     const char *buf, size_t count)		\
4811d200c07SBorislav Petkov {									\
4821d200c07SBorislav Petkov 	struct cacheinfo *this_leaf = dev_get_drvdata(dev);		\
4831d200c07SBorislav Petkov 	return store_cache_disable(this_leaf, buf, count, slot);	\
4841d200c07SBorislav Petkov }
4851d200c07SBorislav Petkov STORE_CACHE_DISABLE(0)
4861d200c07SBorislav Petkov STORE_CACHE_DISABLE(1)
4871d200c07SBorislav Petkov 
subcaches_show(struct device * dev,struct device_attribute * attr,char * buf)4881d200c07SBorislav Petkov static ssize_t subcaches_show(struct device *dev,
4891d200c07SBorislav Petkov 			      struct device_attribute *attr, char *buf)
4901d200c07SBorislav Petkov {
4911d200c07SBorislav Petkov 	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
4921d200c07SBorislav Petkov 	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
4931d200c07SBorislav Petkov 
4941d200c07SBorislav Petkov 	return sprintf(buf, "%x\n", amd_get_subcaches(cpu));
4951d200c07SBorislav Petkov }
4961d200c07SBorislav Petkov 
subcaches_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4971d200c07SBorislav Petkov static ssize_t subcaches_store(struct device *dev,
4981d200c07SBorislav Petkov 			       struct device_attribute *attr,
4991d200c07SBorislav Petkov 			       const char *buf, size_t count)
5001d200c07SBorislav Petkov {
5011d200c07SBorislav Petkov 	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
5021d200c07SBorislav Petkov 	int cpu = cpumask_first(&this_leaf->shared_cpu_map);
5031d200c07SBorislav Petkov 	unsigned long val;
5041d200c07SBorislav Petkov 
5051d200c07SBorislav Petkov 	if (!capable(CAP_SYS_ADMIN))
5061d200c07SBorislav Petkov 		return -EPERM;
5071d200c07SBorislav Petkov 
5081d200c07SBorislav Petkov 	if (kstrtoul(buf, 16, &val) < 0)
5091d200c07SBorislav Petkov 		return -EINVAL;
5101d200c07SBorislav Petkov 
5111d200c07SBorislav Petkov 	if (amd_set_subcaches(cpu, val))
5121d200c07SBorislav Petkov 		return -EINVAL;
5131d200c07SBorislav Petkov 
5141d200c07SBorislav Petkov 	return count;
5151d200c07SBorislav Petkov }
5161d200c07SBorislav Petkov 
5171d200c07SBorislav Petkov static DEVICE_ATTR_RW(cache_disable_0);
5181d200c07SBorislav Petkov static DEVICE_ATTR_RW(cache_disable_1);
5191d200c07SBorislav Petkov static DEVICE_ATTR_RW(subcaches);
5201d200c07SBorislav Petkov 
5211d200c07SBorislav Petkov static umode_t
cache_private_attrs_is_visible(struct kobject * kobj,struct attribute * attr,int unused)5221d200c07SBorislav Petkov cache_private_attrs_is_visible(struct kobject *kobj,
5231d200c07SBorislav Petkov 			       struct attribute *attr, int unused)
5241d200c07SBorislav Petkov {
5251d200c07SBorislav Petkov 	struct device *dev = kobj_to_dev(kobj);
5261d200c07SBorislav Petkov 	struct cacheinfo *this_leaf = dev_get_drvdata(dev);
5271d200c07SBorislav Petkov 	umode_t mode = attr->mode;
5281d200c07SBorislav Petkov 
5291d200c07SBorislav Petkov 	if (!this_leaf->priv)
5301d200c07SBorislav Petkov 		return 0;
5311d200c07SBorislav Petkov 
5321d200c07SBorislav Petkov 	if ((attr == &dev_attr_subcaches.attr) &&
5331d200c07SBorislav Petkov 	    amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
5341d200c07SBorislav Petkov 		return mode;
5351d200c07SBorislav Petkov 
5361d200c07SBorislav Petkov 	if ((attr == &dev_attr_cache_disable_0.attr ||
5371d200c07SBorislav Petkov 	     attr == &dev_attr_cache_disable_1.attr) &&
5381d200c07SBorislav Petkov 	    amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
5391d200c07SBorislav Petkov 		return mode;
5401d200c07SBorislav Petkov 
5411d200c07SBorislav Petkov 	return 0;
5421d200c07SBorislav Petkov }
5431d200c07SBorislav Petkov 
5441d200c07SBorislav Petkov static struct attribute_group cache_private_group = {
5451d200c07SBorislav Petkov 	.is_visible = cache_private_attrs_is_visible,
5461d200c07SBorislav Petkov };
5471d200c07SBorislav Petkov 
init_amd_l3_attrs(void)5481d200c07SBorislav Petkov static void init_amd_l3_attrs(void)
5491d200c07SBorislav Petkov {
5501d200c07SBorislav Petkov 	int n = 1;
5511d200c07SBorislav Petkov 	static struct attribute **amd_l3_attrs;
5521d200c07SBorislav Petkov 
5531d200c07SBorislav Petkov 	if (amd_l3_attrs) /* already initialized */
5541d200c07SBorislav Petkov 		return;
5551d200c07SBorislav Petkov 
5561d200c07SBorislav Petkov 	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))
5571d200c07SBorislav Petkov 		n += 2;
5581d200c07SBorislav Petkov 	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
5591d200c07SBorislav Petkov 		n += 1;
5601d200c07SBorislav Petkov 
5611d200c07SBorislav Petkov 	amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL);
5621d200c07SBorislav Petkov 	if (!amd_l3_attrs)
5631d200c07SBorislav Petkov 		return;
5641d200c07SBorislav Petkov 
5651d200c07SBorislav Petkov 	n = 0;
5661d200c07SBorislav Petkov 	if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {
5671d200c07SBorislav Petkov 		amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr;
5681d200c07SBorislav Petkov 		amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr;
5691d200c07SBorislav Petkov 	}
5701d200c07SBorislav Petkov 	if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
5711d200c07SBorislav Petkov 		amd_l3_attrs[n++] = &dev_attr_subcaches.attr;
5721d200c07SBorislav Petkov 
5731d200c07SBorislav Petkov 	cache_private_group.attrs = amd_l3_attrs;
5741d200c07SBorislav Petkov }
5751d200c07SBorislav Petkov 
5761d200c07SBorislav Petkov const struct attribute_group *
cache_get_priv_group(struct cacheinfo * this_leaf)5771d200c07SBorislav Petkov cache_get_priv_group(struct cacheinfo *this_leaf)
5781d200c07SBorislav Petkov {
5791d200c07SBorislav Petkov 	struct amd_northbridge *nb = this_leaf->priv;
5801d200c07SBorislav Petkov 
5811d200c07SBorislav Petkov 	if (this_leaf->level < 3 || !nb)
5821d200c07SBorislav Petkov 		return NULL;
5831d200c07SBorislav Petkov 
5841d200c07SBorislav Petkov 	if (nb && nb->l3_cache.indices)
5851d200c07SBorislav Petkov 		init_amd_l3_attrs();
5861d200c07SBorislav Petkov 
5871d200c07SBorislav Petkov 	return &cache_private_group;
5881d200c07SBorislav Petkov }
5891d200c07SBorislav Petkov 
amd_init_l3_cache(struct _cpuid4_info_regs * this_leaf,int index)5901d200c07SBorislav Petkov static void amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index)
5911d200c07SBorislav Petkov {
5921d200c07SBorislav Petkov 	int node;
5931d200c07SBorislav Petkov 
5941d200c07SBorislav Petkov 	/* only for L3, and not in virtualized environments */
5951d200c07SBorislav Petkov 	if (index < 3)
5961d200c07SBorislav Petkov 		return;
5971d200c07SBorislav Petkov 
598db970bd2SYazen Ghannam 	node = topology_die_id(smp_processor_id());
5991d200c07SBorislav Petkov 	this_leaf->nb = node_to_amd_nb(node);
6001d200c07SBorislav Petkov 	if (this_leaf->nb && !this_leaf->nb->l3_cache.indices)
6011d200c07SBorislav Petkov 		amd_calc_l3_indices(this_leaf->nb);
6021d200c07SBorislav Petkov }
6031d200c07SBorislav Petkov #else
6041d200c07SBorislav Petkov #define amd_init_l3_cache(x, y)
6051d200c07SBorislav Petkov #endif  /* CONFIG_AMD_NB && CONFIG_SYSFS */
6061d200c07SBorislav Petkov 
6071d200c07SBorislav Petkov static int
cpuid4_cache_lookup_regs(int index,struct _cpuid4_info_regs * this_leaf)6081d200c07SBorislav Petkov cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
6091d200c07SBorislav Petkov {
6101d200c07SBorislav Petkov 	union _cpuid4_leaf_eax	eax;
6111d200c07SBorislav Petkov 	union _cpuid4_leaf_ebx	ebx;
6121d200c07SBorislav Petkov 	union _cpuid4_leaf_ecx	ecx;
6131d200c07SBorislav Petkov 	unsigned		edx;
6141d200c07SBorislav Petkov 
6151d200c07SBorislav Petkov 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
6161d200c07SBorislav Petkov 		if (boot_cpu_has(X86_FEATURE_TOPOEXT))
6171d200c07SBorislav Petkov 			cpuid_count(0x8000001d, index, &eax.full,
6181d200c07SBorislav Petkov 				    &ebx.full, &ecx.full, &edx);
6191d200c07SBorislav Petkov 		else
6201d200c07SBorislav Petkov 			amd_cpuid4(index, &eax, &ebx, &ecx);
6211d200c07SBorislav Petkov 		amd_init_l3_cache(this_leaf, index);
622d4f7423eSPu Wen 	} else if (boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
623d4f7423eSPu Wen 		cpuid_count(0x8000001d, index, &eax.full,
624d4f7423eSPu Wen 			    &ebx.full, &ecx.full, &edx);
625d4f7423eSPu Wen 		amd_init_l3_cache(this_leaf, index);
6261d200c07SBorislav Petkov 	} else {
6271d200c07SBorislav Petkov 		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
6281d200c07SBorislav Petkov 	}
6291d200c07SBorislav Petkov 
6301d200c07SBorislav Petkov 	if (eax.split.type == CTYPE_NULL)
6311d200c07SBorislav Petkov 		return -EIO; /* better error ? */
6321d200c07SBorislav Petkov 
6331d200c07SBorislav Petkov 	this_leaf->eax = eax;
6341d200c07SBorislav Petkov 	this_leaf->ebx = ebx;
6351d200c07SBorislav Petkov 	this_leaf->ecx = ecx;
6361d200c07SBorislav Petkov 	this_leaf->size = (ecx.split.number_of_sets          + 1) *
6371d200c07SBorislav Petkov 			  (ebx.split.coherency_line_size     + 1) *
6381d200c07SBorislav Petkov 			  (ebx.split.physical_line_partition + 1) *
6391d200c07SBorislav Petkov 			  (ebx.split.ways_of_associativity   + 1);
6401d200c07SBorislav Petkov 	return 0;
6411d200c07SBorislav Petkov }
6421d200c07SBorislav Petkov 
find_num_cache_leaves(struct cpuinfo_x86 * c)6431d200c07SBorislav Petkov static int find_num_cache_leaves(struct cpuinfo_x86 *c)
6441d200c07SBorislav Petkov {
6451d200c07SBorislav Petkov 	unsigned int		eax, ebx, ecx, edx, op;
6461d200c07SBorislav Petkov 	union _cpuid4_leaf_eax	cache_eax;
6471d200c07SBorislav Petkov 	int 			i = -1;
6481d200c07SBorislav Petkov 
649d4f7423eSPu Wen 	if (c->x86_vendor == X86_VENDOR_AMD ||
650d4f7423eSPu Wen 	    c->x86_vendor == X86_VENDOR_HYGON)
6511d200c07SBorislav Petkov 		op = 0x8000001d;
6521d200c07SBorislav Petkov 	else
6531d200c07SBorislav Petkov 		op = 4;
6541d200c07SBorislav Petkov 
6551d200c07SBorislav Petkov 	do {
6561d200c07SBorislav Petkov 		++i;
6571d200c07SBorislav Petkov 		/* Do cpuid(op) loop to find out num_cache_leaves */
6581d200c07SBorislav Petkov 		cpuid_count(op, i, &eax, &ebx, &ecx, &edx);
6591d200c07SBorislav Petkov 		cache_eax.full = eax;
6601d200c07SBorislav Petkov 	} while (cache_eax.split.type != CTYPE_NULL);
6611d200c07SBorislav Petkov 	return i;
6621d200c07SBorislav Petkov }
6631d200c07SBorislav Petkov 
cacheinfo_amd_init_llc_id(struct cpuinfo_x86 * c,int cpu)664028c221eSYazen Ghannam void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu)
66568091ee7SSuravee Suthikulpanit {
66668091ee7SSuravee Suthikulpanit 	/*
66768091ee7SSuravee Suthikulpanit 	 * We may have multiple LLCs if L3 caches exist, so check if we
66868091ee7SSuravee Suthikulpanit 	 * have an L3 cache by looking at the L3 cache CPUID leaf.
66968091ee7SSuravee Suthikulpanit 	 */
67068091ee7SSuravee Suthikulpanit 	if (!cpuid_edx(0x80000006))
67168091ee7SSuravee Suthikulpanit 		return;
67268091ee7SSuravee Suthikulpanit 
67368091ee7SSuravee Suthikulpanit 	if (c->x86 < 0x17) {
67468091ee7SSuravee Suthikulpanit 		/* LLC is at the node level. */
675028c221eSYazen Ghannam 		per_cpu(cpu_llc_id, cpu) = c->cpu_die_id;
6761b7aebf0SQian Cai 	} else if (c->x86 == 0x17 && c->x86_model <= 0x1F) {
67768091ee7SSuravee Suthikulpanit 		/*
67868091ee7SSuravee Suthikulpanit 		 * LLC is at the core complex level.
67968091ee7SSuravee Suthikulpanit 		 * Core complex ID is ApicId[3] for these processors.
68068091ee7SSuravee Suthikulpanit 		 */
68168091ee7SSuravee Suthikulpanit 		per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
68268091ee7SSuravee Suthikulpanit 	} else {
68368091ee7SSuravee Suthikulpanit 		/*
68468091ee7SSuravee Suthikulpanit 		 * LLC ID is calculated from the number of threads sharing the
68568091ee7SSuravee Suthikulpanit 		 * cache.
68668091ee7SSuravee Suthikulpanit 		 * */
68768091ee7SSuravee Suthikulpanit 		u32 eax, ebx, ecx, edx, num_sharing_cache = 0;
68868091ee7SSuravee Suthikulpanit 		u32 llc_index = find_num_cache_leaves(c) - 1;
68968091ee7SSuravee Suthikulpanit 
69068091ee7SSuravee Suthikulpanit 		cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
69168091ee7SSuravee Suthikulpanit 		if (eax)
69268091ee7SSuravee Suthikulpanit 			num_sharing_cache = ((eax >> 14) & 0xfff) + 1;
69368091ee7SSuravee Suthikulpanit 
69468091ee7SSuravee Suthikulpanit 		if (num_sharing_cache) {
695964d9784SSuravee Suthikulpanit 			int bits = get_count_order(num_sharing_cache);
69668091ee7SSuravee Suthikulpanit 
69768091ee7SSuravee Suthikulpanit 			per_cpu(cpu_llc_id, cpu) = c->apicid >> bits;
69868091ee7SSuravee Suthikulpanit 		}
69968091ee7SSuravee Suthikulpanit 	}
70068091ee7SSuravee Suthikulpanit }
70168091ee7SSuravee Suthikulpanit 
cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 * c,int cpu)702028c221eSYazen Ghannam void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c, int cpu)
703d4f7423eSPu Wen {
704d4f7423eSPu Wen 	/*
705d4f7423eSPu Wen 	 * We may have multiple LLCs if L3 caches exist, so check if we
706d4f7423eSPu Wen 	 * have an L3 cache by looking at the L3 cache CPUID leaf.
707d4f7423eSPu Wen 	 */
708d4f7423eSPu Wen 	if (!cpuid_edx(0x80000006))
709d4f7423eSPu Wen 		return;
710d4f7423eSPu Wen 
711d4f7423eSPu Wen 	/*
712d4f7423eSPu Wen 	 * LLC is at the core complex level.
713d4f7423eSPu Wen 	 * Core complex ID is ApicId[3] for these processors.
714d4f7423eSPu Wen 	 */
715d4f7423eSPu Wen 	per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
716d4f7423eSPu Wen }
717d4f7423eSPu Wen 
init_amd_cacheinfo(struct cpuinfo_x86 * c)7181d200c07SBorislav Petkov void init_amd_cacheinfo(struct cpuinfo_x86 *c)
7191d200c07SBorislav Petkov {
7201d200c07SBorislav Petkov 
7211d200c07SBorislav Petkov 	if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
7221d200c07SBorislav Petkov 		num_cache_leaves = find_num_cache_leaves(c);
7231d200c07SBorislav Petkov 	} else if (c->extended_cpuid_level >= 0x80000006) {
7241d200c07SBorislav Petkov 		if (cpuid_edx(0x80000006) & 0xf000)
7251d200c07SBorislav Petkov 			num_cache_leaves = 4;
7261d200c07SBorislav Petkov 		else
7271d200c07SBorislav Petkov 			num_cache_leaves = 3;
7281d200c07SBorislav Petkov 	}
7291d200c07SBorislav Petkov }
7301d200c07SBorislav Petkov 
init_hygon_cacheinfo(struct cpuinfo_x86 * c)731d4f7423eSPu Wen void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
732d4f7423eSPu Wen {
733d4f7423eSPu Wen 	num_cache_leaves = find_num_cache_leaves(c);
734d4f7423eSPu Wen }
735d4f7423eSPu Wen 
init_intel_cacheinfo(struct cpuinfo_x86 * c)736807e9bc8SDavid Wang void init_intel_cacheinfo(struct cpuinfo_x86 *c)
7371d200c07SBorislav Petkov {
7381d200c07SBorislav Petkov 	/* Cache sizes */
739851026a2SBorislav Petkov (AMD) 	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0;
7401d200c07SBorislav Petkov 	unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
7411d200c07SBorislav Petkov 	unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
7421d200c07SBorislav Petkov 	unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
7431d200c07SBorislav Petkov #ifdef CONFIG_SMP
7441d200c07SBorislav Petkov 	unsigned int cpu = c->cpu_index;
7451d200c07SBorislav Petkov #endif
7461d200c07SBorislav Petkov 
7471d200c07SBorislav Petkov 	if (c->cpuid_level > 3) {
7481d200c07SBorislav Petkov 		static int is_initialized;
7491d200c07SBorislav Petkov 
7501d200c07SBorislav Petkov 		if (is_initialized == 0) {
7511d200c07SBorislav Petkov 			/* Init num_cache_leaves from boot CPU */
7521d200c07SBorislav Petkov 			num_cache_leaves = find_num_cache_leaves(c);
7531d200c07SBorislav Petkov 			is_initialized++;
7541d200c07SBorislav Petkov 		}
7551d200c07SBorislav Petkov 
7561d200c07SBorislav Petkov 		/*
7571d200c07SBorislav Petkov 		 * Whenever possible use cpuid(4), deterministic cache
7581d200c07SBorislav Petkov 		 * parameters cpuid leaf to find the cache details
7591d200c07SBorislav Petkov 		 */
7601d200c07SBorislav Petkov 		for (i = 0; i < num_cache_leaves; i++) {
7611d200c07SBorislav Petkov 			struct _cpuid4_info_regs this_leaf = {};
7621d200c07SBorislav Petkov 			int retval;
7631d200c07SBorislav Petkov 
7641d200c07SBorislav Petkov 			retval = cpuid4_cache_lookup_regs(i, &this_leaf);
7651d200c07SBorislav Petkov 			if (retval < 0)
7661d200c07SBorislav Petkov 				continue;
7671d200c07SBorislav Petkov 
7681d200c07SBorislav Petkov 			switch (this_leaf.eax.split.level) {
7691d200c07SBorislav Petkov 			case 1:
7701d200c07SBorislav Petkov 				if (this_leaf.eax.split.type == CTYPE_DATA)
7711d200c07SBorislav Petkov 					new_l1d = this_leaf.size/1024;
7721d200c07SBorislav Petkov 				else if (this_leaf.eax.split.type == CTYPE_INST)
7731d200c07SBorislav Petkov 					new_l1i = this_leaf.size/1024;
7741d200c07SBorislav Petkov 				break;
7751d200c07SBorislav Petkov 			case 2:
7761d200c07SBorislav Petkov 				new_l2 = this_leaf.size/1024;
7771d200c07SBorislav Petkov 				num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
7781d200c07SBorislav Petkov 				index_msb = get_count_order(num_threads_sharing);
7791d200c07SBorislav Petkov 				l2_id = c->apicid & ~((1 << index_msb) - 1);
7801d200c07SBorislav Petkov 				break;
7811d200c07SBorislav Petkov 			case 3:
7821d200c07SBorislav Petkov 				new_l3 = this_leaf.size/1024;
7831d200c07SBorislav Petkov 				num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
7841d200c07SBorislav Petkov 				index_msb = get_count_order(num_threads_sharing);
7851d200c07SBorislav Petkov 				l3_id = c->apicid & ~((1 << index_msb) - 1);
7861d200c07SBorislav Petkov 				break;
7871d200c07SBorislav Petkov 			default:
7881d200c07SBorislav Petkov 				break;
7891d200c07SBorislav Petkov 			}
7901d200c07SBorislav Petkov 		}
7911d200c07SBorislav Petkov 	}
7921d200c07SBorislav Petkov 	/*
7931d200c07SBorislav Petkov 	 * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
7941d200c07SBorislav Petkov 	 * trace cache
7951d200c07SBorislav Petkov 	 */
7961d200c07SBorislav Petkov 	if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
7971d200c07SBorislav Petkov 		/* supports eax=2  call */
7981d200c07SBorislav Petkov 		int j, n;
7991d200c07SBorislav Petkov 		unsigned int regs[4];
8001d200c07SBorislav Petkov 		unsigned char *dp = (unsigned char *)regs;
8011d200c07SBorislav Petkov 		int only_trace = 0;
8021d200c07SBorislav Petkov 
8031d200c07SBorislav Petkov 		if (num_cache_leaves != 0 && c->x86 == 15)
8041d200c07SBorislav Petkov 			only_trace = 1;
8051d200c07SBorislav Petkov 
8061d200c07SBorislav Petkov 		/* Number of times to iterate */
8071d200c07SBorislav Petkov 		n = cpuid_eax(2) & 0xFF;
8081d200c07SBorislav Petkov 
8091d200c07SBorislav Petkov 		for (i = 0 ; i < n ; i++) {
8101d200c07SBorislav Petkov 			cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
8111d200c07SBorislav Petkov 
8121d200c07SBorislav Petkov 			/* If bit 31 is set, this is an unknown format */
813*db79249bSAhmed S. Darwish 			for (j = 0 ; j < 4 ; j++)
8141d200c07SBorislav Petkov 				if (regs[j] & (1 << 31))
8151d200c07SBorislav Petkov 					regs[j] = 0;
8161d200c07SBorislav Petkov 
8171d200c07SBorislav Petkov 			/* Byte 0 is level count, not a descriptor */
8181d200c07SBorislav Petkov 			for (j = 1 ; j < 16 ; j++) {
8191d200c07SBorislav Petkov 				unsigned char des = dp[j];
8201d200c07SBorislav Petkov 				unsigned char k = 0;
8211d200c07SBorislav Petkov 
8221d200c07SBorislav Petkov 				/* look up this descriptor in the table */
8231d200c07SBorislav Petkov 				while (cache_table[k].descriptor != 0) {
8241d200c07SBorislav Petkov 					if (cache_table[k].descriptor == des) {
8251d200c07SBorislav Petkov 						if (only_trace && cache_table[k].cache_type != LVL_TRACE)
8261d200c07SBorislav Petkov 							break;
8271d200c07SBorislav Petkov 						switch (cache_table[k].cache_type) {
8281d200c07SBorislav Petkov 						case LVL_1_INST:
8291d200c07SBorislav Petkov 							l1i += cache_table[k].size;
8301d200c07SBorislav Petkov 							break;
8311d200c07SBorislav Petkov 						case LVL_1_DATA:
8321d200c07SBorislav Petkov 							l1d += cache_table[k].size;
8331d200c07SBorislav Petkov 							break;
8341d200c07SBorislav Petkov 						case LVL_2:
8351d200c07SBorislav Petkov 							l2 += cache_table[k].size;
8361d200c07SBorislav Petkov 							break;
8371d200c07SBorislav Petkov 						case LVL_3:
8381d200c07SBorislav Petkov 							l3 += cache_table[k].size;
8391d200c07SBorislav Petkov 							break;
8401d200c07SBorislav Petkov 						}
8411d200c07SBorislav Petkov 
8421d200c07SBorislav Petkov 						break;
8431d200c07SBorislav Petkov 					}
8441d200c07SBorislav Petkov 
8451d200c07SBorislav Petkov 					k++;
8461d200c07SBorislav Petkov 				}
8471d200c07SBorislav Petkov 			}
8481d200c07SBorislav Petkov 		}
8491d200c07SBorislav Petkov 	}
8501d200c07SBorislav Petkov 
8511d200c07SBorislav Petkov 	if (new_l1d)
8521d200c07SBorislav Petkov 		l1d = new_l1d;
8531d200c07SBorislav Petkov 
8541d200c07SBorislav Petkov 	if (new_l1i)
8551d200c07SBorislav Petkov 		l1i = new_l1i;
8561d200c07SBorislav Petkov 
8571d200c07SBorislav Petkov 	if (new_l2) {
8581d200c07SBorislav Petkov 		l2 = new_l2;
8591d200c07SBorislav Petkov #ifdef CONFIG_SMP
8601d200c07SBorislav Petkov 		per_cpu(cpu_llc_id, cpu) = l2_id;
86166558b73STim Chen 		per_cpu(cpu_l2c_id, cpu) = l2_id;
8621d200c07SBorislav Petkov #endif
8631d200c07SBorislav Petkov 	}
8641d200c07SBorislav Petkov 
8651d200c07SBorislav Petkov 	if (new_l3) {
8661d200c07SBorislav Petkov 		l3 = new_l3;
8671d200c07SBorislav Petkov #ifdef CONFIG_SMP
8681d200c07SBorislav Petkov 		per_cpu(cpu_llc_id, cpu) = l3_id;
8691d200c07SBorislav Petkov #endif
8701d200c07SBorislav Petkov 	}
8711d200c07SBorislav Petkov 
8721d200c07SBorislav Petkov #ifdef CONFIG_SMP
8731d200c07SBorislav Petkov 	/*
8741d200c07SBorislav Petkov 	 * If cpu_llc_id is not yet set, this means cpuid_level < 4 which in
8751d200c07SBorislav Petkov 	 * turns means that the only possibility is SMT (as indicated in
8761d200c07SBorislav Petkov 	 * cpuid1). Since cpuid2 doesn't specify shared caches, and we know
8771d200c07SBorislav Petkov 	 * that SMT shares all caches, we can unconditionally set cpu_llc_id to
8781d200c07SBorislav Petkov 	 * c->phys_proc_id.
8791d200c07SBorislav Petkov 	 */
8801d200c07SBorislav Petkov 	if (per_cpu(cpu_llc_id, cpu) == BAD_APICID)
8811d200c07SBorislav Petkov 		per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
8821d200c07SBorislav Petkov #endif
8831d200c07SBorislav Petkov 
8841d200c07SBorislav Petkov 	c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
8851d200c07SBorislav Petkov 
886807e9bc8SDavid Wang 	if (!l2)
887807e9bc8SDavid Wang 		cpu_detect_cache_sizes(c);
8881d200c07SBorislav Petkov }
8891d200c07SBorislav Petkov 
__cache_amd_cpumap_setup(unsigned int cpu,int index,struct _cpuid4_info_regs * base)8901d200c07SBorislav Petkov static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
8911d200c07SBorislav Petkov 				    struct _cpuid4_info_regs *base)
8921d200c07SBorislav Petkov {
893dda451f3SYang Li 	struct cpu_cacheinfo *this_cpu_ci;
8941d200c07SBorislav Petkov 	struct cacheinfo *this_leaf;
8951d200c07SBorislav Petkov 	int i, sibling;
8961d200c07SBorislav Petkov 
8971d200c07SBorislav Petkov 	/*
8981d200c07SBorislav Petkov 	 * For L3, always use the pre-calculated cpu_llc_shared_mask
8991d200c07SBorislav Petkov 	 * to derive shared_cpu_map.
9001d200c07SBorislav Petkov 	 */
9011d200c07SBorislav Petkov 	if (index == 3) {
9021d200c07SBorislav Petkov 		for_each_cpu(i, cpu_llc_shared_mask(cpu)) {
9031d200c07SBorislav Petkov 			this_cpu_ci = get_cpu_cacheinfo(i);
9041d200c07SBorislav Petkov 			if (!this_cpu_ci->info_list)
9051d200c07SBorislav Petkov 				continue;
9061d200c07SBorislav Petkov 			this_leaf = this_cpu_ci->info_list + index;
9071d200c07SBorislav Petkov 			for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {
9081d200c07SBorislav Petkov 				if (!cpu_online(sibling))
9091d200c07SBorislav Petkov 					continue;
9101d200c07SBorislav Petkov 				cpumask_set_cpu(sibling,
9111d200c07SBorislav Petkov 						&this_leaf->shared_cpu_map);
9121d200c07SBorislav Petkov 			}
9131d200c07SBorislav Petkov 		}
9141d200c07SBorislav Petkov 	} else if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
9151d200c07SBorislav Petkov 		unsigned int apicid, nshared, first, last;
9161d200c07SBorislav Petkov 
9171d200c07SBorislav Petkov 		nshared = base->eax.split.num_threads_sharing + 1;
9181d200c07SBorislav Petkov 		apicid = cpu_data(cpu).apicid;
9191d200c07SBorislav Petkov 		first = apicid - (apicid % nshared);
9201d200c07SBorislav Petkov 		last = first + nshared - 1;
9211d200c07SBorislav Petkov 
9221d200c07SBorislav Petkov 		for_each_online_cpu(i) {
9231d200c07SBorislav Petkov 			this_cpu_ci = get_cpu_cacheinfo(i);
9241d200c07SBorislav Petkov 			if (!this_cpu_ci->info_list)
9251d200c07SBorislav Petkov 				continue;
9261d200c07SBorislav Petkov 
9271d200c07SBorislav Petkov 			apicid = cpu_data(i).apicid;
9281d200c07SBorislav Petkov 			if ((apicid < first) || (apicid > last))
9291d200c07SBorislav Petkov 				continue;
9301d200c07SBorislav Petkov 
9311d200c07SBorislav Petkov 			this_leaf = this_cpu_ci->info_list + index;
9321d200c07SBorislav Petkov 
9331d200c07SBorislav Petkov 			for_each_online_cpu(sibling) {
9341d200c07SBorislav Petkov 				apicid = cpu_data(sibling).apicid;
9351d200c07SBorislav Petkov 				if ((apicid < first) || (apicid > last))
9361d200c07SBorislav Petkov 					continue;
9371d200c07SBorislav Petkov 				cpumask_set_cpu(sibling,
9381d200c07SBorislav Petkov 						&this_leaf->shared_cpu_map);
9391d200c07SBorislav Petkov 			}
9401d200c07SBorislav Petkov 		}
9411d200c07SBorislav Petkov 	} else
9421d200c07SBorislav Petkov 		return 0;
9431d200c07SBorislav Petkov 
9441d200c07SBorislav Petkov 	return 1;
9451d200c07SBorislav Petkov }
9461d200c07SBorislav Petkov 
__cache_cpumap_setup(unsigned int cpu,int index,struct _cpuid4_info_regs * base)9471d200c07SBorislav Petkov static void __cache_cpumap_setup(unsigned int cpu, int index,
9481d200c07SBorislav Petkov 				 struct _cpuid4_info_regs *base)
9491d200c07SBorislav Petkov {
9501d200c07SBorislav Petkov 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
9511d200c07SBorislav Petkov 	struct cacheinfo *this_leaf, *sibling_leaf;
9521d200c07SBorislav Petkov 	unsigned long num_threads_sharing;
9531d200c07SBorislav Petkov 	int index_msb, i;
9541d200c07SBorislav Petkov 	struct cpuinfo_x86 *c = &cpu_data(cpu);
9551d200c07SBorislav Petkov 
956d4f7423eSPu Wen 	if (c->x86_vendor == X86_VENDOR_AMD ||
957d4f7423eSPu Wen 	    c->x86_vendor == X86_VENDOR_HYGON) {
9581d200c07SBorislav Petkov 		if (__cache_amd_cpumap_setup(cpu, index, base))
9591d200c07SBorislav Petkov 			return;
9601d200c07SBorislav Petkov 	}
9611d200c07SBorislav Petkov 
9621d200c07SBorislav Petkov 	this_leaf = this_cpu_ci->info_list + index;
9631d200c07SBorislav Petkov 	num_threads_sharing = 1 + base->eax.split.num_threads_sharing;
9641d200c07SBorislav Petkov 
9651d200c07SBorislav Petkov 	cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map);
9661d200c07SBorislav Petkov 	if (num_threads_sharing == 1)
9671d200c07SBorislav Petkov 		return;
9681d200c07SBorislav Petkov 
9691d200c07SBorislav Petkov 	index_msb = get_count_order(num_threads_sharing);
9701d200c07SBorislav Petkov 
9711d200c07SBorislav Petkov 	for_each_online_cpu(i)
9721d200c07SBorislav Petkov 		if (cpu_data(i).apicid >> index_msb == c->apicid >> index_msb) {
9731d200c07SBorislav Petkov 			struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i);
9741d200c07SBorislav Petkov 
9751d200c07SBorislav Petkov 			if (i == cpu || !sib_cpu_ci->info_list)
9761d200c07SBorislav Petkov 				continue;/* skip if itself or no cacheinfo */
9771d200c07SBorislav Petkov 			sibling_leaf = sib_cpu_ci->info_list + index;
9781d200c07SBorislav Petkov 			cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
9791d200c07SBorislav Petkov 			cpumask_set_cpu(cpu, &sibling_leaf->shared_cpu_map);
9801d200c07SBorislav Petkov 		}
9811d200c07SBorislav Petkov }
9821d200c07SBorislav Petkov 
ci_leaf_init(struct cacheinfo * this_leaf,struct _cpuid4_info_regs * base)9831d200c07SBorislav Petkov static void ci_leaf_init(struct cacheinfo *this_leaf,
9841d200c07SBorislav Petkov 			 struct _cpuid4_info_regs *base)
9851d200c07SBorislav Petkov {
9861d200c07SBorislav Petkov 	this_leaf->id = base->id;
9871d200c07SBorislav Petkov 	this_leaf->attributes = CACHE_ID;
9881d200c07SBorislav Petkov 	this_leaf->level = base->eax.split.level;
9891d200c07SBorislav Petkov 	this_leaf->type = cache_type_map[base->eax.split.type];
9901d200c07SBorislav Petkov 	this_leaf->coherency_line_size =
9911d200c07SBorislav Petkov 				base->ebx.split.coherency_line_size + 1;
9921d200c07SBorislav Petkov 	this_leaf->ways_of_associativity =
9931d200c07SBorislav Petkov 				base->ebx.split.ways_of_associativity + 1;
9941d200c07SBorislav Petkov 	this_leaf->size = base->size;
9951d200c07SBorislav Petkov 	this_leaf->number_of_sets = base->ecx.split.number_of_sets + 1;
9961d200c07SBorislav Petkov 	this_leaf->physical_line_partition =
9971d200c07SBorislav Petkov 				base->ebx.split.physical_line_partition + 1;
9981d200c07SBorislav Petkov 	this_leaf->priv = base->nb;
9991d200c07SBorislav Petkov }
10001d200c07SBorislav Petkov 
init_cache_level(unsigned int cpu)10014b92d4adSThomas Gleixner int init_cache_level(unsigned int cpu)
10021d200c07SBorislav Petkov {
10031d200c07SBorislav Petkov 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
10041d200c07SBorislav Petkov 
10051d200c07SBorislav Petkov 	if (!num_cache_leaves)
10061d200c07SBorislav Petkov 		return -ENOENT;
10071d200c07SBorislav Petkov 	if (!this_cpu_ci)
10081d200c07SBorislav Petkov 		return -EINVAL;
10091d200c07SBorislav Petkov 	this_cpu_ci->num_levels = 3;
10101d200c07SBorislav Petkov 	this_cpu_ci->num_leaves = num_cache_leaves;
10111d200c07SBorislav Petkov 	return 0;
10121d200c07SBorislav Petkov }
10131d200c07SBorislav Petkov 
10141d200c07SBorislav Petkov /*
10151d200c07SBorislav Petkov  * The max shared threads number comes from CPUID.4:EAX[25-14] with input
10161d200c07SBorislav Petkov  * ECX as cache index. Then right shift apicid by the number's order to get
10171d200c07SBorislav Petkov  * cache id for this cache node.
10181d200c07SBorislav Petkov  */
get_cache_id(int cpu,struct _cpuid4_info_regs * id4_regs)10191d200c07SBorislav Petkov static void get_cache_id(int cpu, struct _cpuid4_info_regs *id4_regs)
10201d200c07SBorislav Petkov {
10211d200c07SBorislav Petkov 	struct cpuinfo_x86 *c = &cpu_data(cpu);
10221d200c07SBorislav Petkov 	unsigned long num_threads_sharing;
10231d200c07SBorislav Petkov 	int index_msb;
10241d200c07SBorislav Petkov 
10251d200c07SBorislav Petkov 	num_threads_sharing = 1 + id4_regs->eax.split.num_threads_sharing;
10261d200c07SBorislav Petkov 	index_msb = get_count_order(num_threads_sharing);
10271d200c07SBorislav Petkov 	id4_regs->id = c->apicid >> index_msb;
10281d200c07SBorislav Petkov }
10291d200c07SBorislav Petkov 
populate_cache_leaves(unsigned int cpu)10304b92d4adSThomas Gleixner int populate_cache_leaves(unsigned int cpu)
10311d200c07SBorislav Petkov {
10321d200c07SBorislav Petkov 	unsigned int idx, ret;
10331d200c07SBorislav Petkov 	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
10341d200c07SBorislav Petkov 	struct cacheinfo *this_leaf = this_cpu_ci->info_list;
10351d200c07SBorislav Petkov 	struct _cpuid4_info_regs id4_regs = {};
10361d200c07SBorislav Petkov 
10371d200c07SBorislav Petkov 	for (idx = 0; idx < this_cpu_ci->num_leaves; idx++) {
10381d200c07SBorislav Petkov 		ret = cpuid4_cache_lookup_regs(idx, &id4_regs);
10391d200c07SBorislav Petkov 		if (ret)
10401d200c07SBorislav Petkov 			return ret;
10411d200c07SBorislav Petkov 		get_cache_id(cpu, &id4_regs);
10421d200c07SBorislav Petkov 		ci_leaf_init(this_leaf++, &id4_regs);
10431d200c07SBorislav Petkov 		__cache_cpumap_setup(cpu, idx, &id4_regs);
10441d200c07SBorislav Petkov 	}
10451d200c07SBorislav Petkov 	this_cpu_ci->cpu_map_populated = true;
10461d200c07SBorislav Petkov 
10471d200c07SBorislav Petkov 	return 0;
10481d200c07SBorislav Petkov }
104923a63e36SJuergen Gross 
105023a63e36SJuergen Gross /*
105123a63e36SJuergen Gross  * Disable and enable caches. Needed for changing MTRRs and the PAT MSR.
105223a63e36SJuergen Gross  *
105323a63e36SJuergen Gross  * Since we are disabling the cache don't allow any interrupts,
105423a63e36SJuergen Gross  * they would run extremely slow and would only increase the pain.
105523a63e36SJuergen Gross  *
105623a63e36SJuergen Gross  * The caller must ensure that local interrupts are disabled and
105723a63e36SJuergen Gross  * are reenabled after cache_enable() has been called.
105823a63e36SJuergen Gross  */
105923a63e36SJuergen Gross static unsigned long saved_cr4;
106023a63e36SJuergen Gross static DEFINE_RAW_SPINLOCK(cache_disable_lock);
106123a63e36SJuergen Gross 
cache_disable(void)106223a63e36SJuergen Gross void cache_disable(void) __acquires(cache_disable_lock)
106323a63e36SJuergen Gross {
106423a63e36SJuergen Gross 	unsigned long cr0;
106523a63e36SJuergen Gross 
106623a63e36SJuergen Gross 	/*
106723a63e36SJuergen Gross 	 * Note that this is not ideal
106823a63e36SJuergen Gross 	 * since the cache is only flushed/disabled for this CPU while the
106923a63e36SJuergen Gross 	 * MTRRs are changed, but changing this requires more invasive
107023a63e36SJuergen Gross 	 * changes to the way the kernel boots
107123a63e36SJuergen Gross 	 */
107223a63e36SJuergen Gross 
107323a63e36SJuergen Gross 	raw_spin_lock(&cache_disable_lock);
107423a63e36SJuergen Gross 
107523a63e36SJuergen Gross 	/* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */
107623a63e36SJuergen Gross 	cr0 = read_cr0() | X86_CR0_CD;
107723a63e36SJuergen Gross 	write_cr0(cr0);
107823a63e36SJuergen Gross 
107923a63e36SJuergen Gross 	/*
108023a63e36SJuergen Gross 	 * Cache flushing is the most time-consuming step when programming
108123a63e36SJuergen Gross 	 * the MTRRs. Fortunately, as per the Intel Software Development
108223a63e36SJuergen Gross 	 * Manual, we can skip it if the processor supports cache self-
108323a63e36SJuergen Gross 	 * snooping.
108423a63e36SJuergen Gross 	 */
108523a63e36SJuergen Gross 	if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
108623a63e36SJuergen Gross 		wbinvd();
108723a63e36SJuergen Gross 
108823a63e36SJuergen Gross 	/* Save value of CR4 and clear Page Global Enable (bit 7) */
108923a63e36SJuergen Gross 	if (cpu_feature_enabled(X86_FEATURE_PGE)) {
109023a63e36SJuergen Gross 		saved_cr4 = __read_cr4();
109123a63e36SJuergen Gross 		__write_cr4(saved_cr4 & ~X86_CR4_PGE);
109223a63e36SJuergen Gross 	}
109323a63e36SJuergen Gross 
109423a63e36SJuergen Gross 	/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
109523a63e36SJuergen Gross 	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
109623a63e36SJuergen Gross 	flush_tlb_local();
109723a63e36SJuergen Gross 
109823a63e36SJuergen Gross 	if (cpu_feature_enabled(X86_FEATURE_MTRR))
109923a63e36SJuergen Gross 		mtrr_disable();
110023a63e36SJuergen Gross 
110123a63e36SJuergen Gross 	/* Again, only flush caches if we have to. */
110223a63e36SJuergen Gross 	if (!static_cpu_has(X86_FEATURE_SELFSNOOP))
110323a63e36SJuergen Gross 		wbinvd();
110423a63e36SJuergen Gross }
110523a63e36SJuergen Gross 
cache_enable(void)110623a63e36SJuergen Gross void cache_enable(void) __releases(cache_disable_lock)
110723a63e36SJuergen Gross {
110823a63e36SJuergen Gross 	/* Flush TLBs (no need to flush caches - they are disabled) */
110923a63e36SJuergen Gross 	count_vm_tlb_event(NR_TLB_LOCAL_FLUSH_ALL);
111023a63e36SJuergen Gross 	flush_tlb_local();
111123a63e36SJuergen Gross 
111223a63e36SJuergen Gross 	if (cpu_feature_enabled(X86_FEATURE_MTRR))
111323a63e36SJuergen Gross 		mtrr_enable();
111423a63e36SJuergen Gross 
111523a63e36SJuergen Gross 	/* Enable caches */
111623a63e36SJuergen Gross 	write_cr0(read_cr0() & ~X86_CR0_CD);
111723a63e36SJuergen Gross 
111823a63e36SJuergen Gross 	/* Restore value of CR4 */
111923a63e36SJuergen Gross 	if (cpu_feature_enabled(X86_FEATURE_PGE))
112023a63e36SJuergen Gross 		__write_cr4(saved_cr4);
112123a63e36SJuergen Gross 
112223a63e36SJuergen Gross 	raw_spin_unlock(&cache_disable_lock);
112323a63e36SJuergen Gross }
11247d71db53SJuergen Gross 
cache_cpu_init(void)11250b9a6a8bSJuergen Gross static void cache_cpu_init(void)
11267d71db53SJuergen Gross {
11277d71db53SJuergen Gross 	unsigned long flags;
11287d71db53SJuergen Gross 
11297d71db53SJuergen Gross 	local_irq_save(flags);
11307d71db53SJuergen Gross 	cache_disable();
11317d71db53SJuergen Gross 
11327d71db53SJuergen Gross 	if (memory_caching_control & CACHE_MTRR)
11337d71db53SJuergen Gross 		mtrr_generic_set_state();
11347d71db53SJuergen Gross 
11357d71db53SJuergen Gross 	if (memory_caching_control & CACHE_PAT)
1136adfe7512SJuergen Gross 		pat_cpu_init();
11377d71db53SJuergen Gross 
11387d71db53SJuergen Gross 	cache_enable();
11397d71db53SJuergen Gross 	local_irq_restore(flags);
11407d71db53SJuergen Gross }
1141955d0e08SJuergen Gross 
114230f89e52SJuergen Gross static bool cache_aps_delayed_init = true;
1143955d0e08SJuergen Gross 
set_cache_aps_delayed_init(bool val)1144955d0e08SJuergen Gross void set_cache_aps_delayed_init(bool val)
1145955d0e08SJuergen Gross {
1146955d0e08SJuergen Gross 	cache_aps_delayed_init = val;
1147955d0e08SJuergen Gross }
1148955d0e08SJuergen Gross 
get_cache_aps_delayed_init(void)1149955d0e08SJuergen Gross bool get_cache_aps_delayed_init(void)
1150955d0e08SJuergen Gross {
1151955d0e08SJuergen Gross 	return cache_aps_delayed_init;
1152955d0e08SJuergen Gross }
11530b9a6a8bSJuergen Gross 
cache_rendezvous_handler(void * unused)11540b9a6a8bSJuergen Gross static int cache_rendezvous_handler(void *unused)
11550b9a6a8bSJuergen Gross {
11560b9a6a8bSJuergen Gross 	if (get_cache_aps_delayed_init() || !cpu_online(smp_processor_id()))
11570b9a6a8bSJuergen Gross 		cache_cpu_init();
11580b9a6a8bSJuergen Gross 
11590b9a6a8bSJuergen Gross 	return 0;
11600b9a6a8bSJuergen Gross }
11610b9a6a8bSJuergen Gross 
cache_bp_init(void)11620b9a6a8bSJuergen Gross void __init cache_bp_init(void)
11630b9a6a8bSJuergen Gross {
11640b9a6a8bSJuergen Gross 	mtrr_bp_init();
1165adfe7512SJuergen Gross 	pat_bp_init();
11660b9a6a8bSJuergen Gross 
11670b9a6a8bSJuergen Gross 	if (memory_caching_control)
11680b9a6a8bSJuergen Gross 		cache_cpu_init();
11690b9a6a8bSJuergen Gross }
11700b9a6a8bSJuergen Gross 
cache_bp_restore(void)11710b9a6a8bSJuergen Gross void cache_bp_restore(void)
11720b9a6a8bSJuergen Gross {
11730b9a6a8bSJuergen Gross 	if (memory_caching_control)
11740b9a6a8bSJuergen Gross 		cache_cpu_init();
11750b9a6a8bSJuergen Gross }
11760b9a6a8bSJuergen Gross 
cache_ap_online(unsigned int cpu)1177a32226faSThomas Gleixner static int cache_ap_online(unsigned int cpu)
11780b9a6a8bSJuergen Gross {
1179a32226faSThomas Gleixner 	cpumask_set_cpu(cpu, cpu_cacheinfo_mask);
1180a32226faSThomas Gleixner 
11810b9a6a8bSJuergen Gross 	if (!memory_caching_control || get_cache_aps_delayed_init())
118230f89e52SJuergen Gross 		return 0;
11830b9a6a8bSJuergen Gross 
11840b9a6a8bSJuergen Gross 	/*
11850b9a6a8bSJuergen Gross 	 * Ideally we should hold mtrr_mutex here to avoid MTRR entries
11860b9a6a8bSJuergen Gross 	 * changed, but this routine will be called in CPU boot time,
11870b9a6a8bSJuergen Gross 	 * holding the lock breaks it.
11880b9a6a8bSJuergen Gross 	 *
11890b9a6a8bSJuergen Gross 	 * This routine is called in two cases:
11900b9a6a8bSJuergen Gross 	 *
11910b9a6a8bSJuergen Gross 	 *   1. very early time of software resume, when there absolutely
11920b9a6a8bSJuergen Gross 	 *      isn't MTRR entry changes;
11930b9a6a8bSJuergen Gross 	 *
11940b9a6a8bSJuergen Gross 	 *   2. CPU hotadd time. We let mtrr_add/del_page hold cpuhotplug
11950b9a6a8bSJuergen Gross 	 *      lock to prevent MTRR entry changes
11960b9a6a8bSJuergen Gross 	 */
11970b9a6a8bSJuergen Gross 	stop_machine_from_inactive_cpu(cache_rendezvous_handler, NULL,
1198a32226faSThomas Gleixner 				       cpu_cacheinfo_mask);
119930f89e52SJuergen Gross 
120030f89e52SJuergen Gross 	return 0;
12010b9a6a8bSJuergen Gross }
12020b9a6a8bSJuergen Gross 
cache_ap_offline(unsigned int cpu)1203a32226faSThomas Gleixner static int cache_ap_offline(unsigned int cpu)
1204a32226faSThomas Gleixner {
1205a32226faSThomas Gleixner 	cpumask_clear_cpu(cpu, cpu_cacheinfo_mask);
1206a32226faSThomas Gleixner 	return 0;
1207a32226faSThomas Gleixner }
1208a32226faSThomas Gleixner 
12090b9a6a8bSJuergen Gross /*
12100b9a6a8bSJuergen Gross  * Delayed cache initialization for all AP's
12110b9a6a8bSJuergen Gross  */
cache_aps_init(void)12120b9a6a8bSJuergen Gross void cache_aps_init(void)
12130b9a6a8bSJuergen Gross {
12140b9a6a8bSJuergen Gross 	if (!memory_caching_control || !get_cache_aps_delayed_init())
12150b9a6a8bSJuergen Gross 		return;
12160b9a6a8bSJuergen Gross 
12170b9a6a8bSJuergen Gross 	stop_machine(cache_rendezvous_handler, NULL, cpu_online_mask);
12180b9a6a8bSJuergen Gross 	set_cache_aps_delayed_init(false);
12190b9a6a8bSJuergen Gross }
122030f89e52SJuergen Gross 
cache_ap_register(void)122130f89e52SJuergen Gross static int __init cache_ap_register(void)
122230f89e52SJuergen Gross {
1223a32226faSThomas Gleixner 	zalloc_cpumask_var(&cpu_cacheinfo_mask, GFP_KERNEL);
1224a32226faSThomas Gleixner 	cpumask_set_cpu(smp_processor_id(), cpu_cacheinfo_mask);
1225a32226faSThomas Gleixner 
122630f89e52SJuergen Gross 	cpuhp_setup_state_nocalls(CPUHP_AP_CACHECTRL_STARTING,
122730f89e52SJuergen Gross 				  "x86/cachectrl:starting",
1228a32226faSThomas Gleixner 				  cache_ap_online, cache_ap_offline);
122930f89e52SJuergen Gross 	return 0;
123030f89e52SJuergen Gross }
1231a32226faSThomas Gleixner early_initcall(cache_ap_register);
1232