1365e960dSAhmed S. Darwish // SPDX-License-Identifier: GPL-2.0 2365e960dSAhmed S. Darwish /* 3365e960dSAhmed S. Darwish * AMD L3 cache_disable_{0,1} sysfs handling 4365e960dSAhmed S. Darwish * Documentation/ABI/testing/sysfs-devices-system-cpu 5365e960dSAhmed S. Darwish */ 6365e960dSAhmed S. Darwish 7365e960dSAhmed S. Darwish #include <linux/cacheinfo.h> 8365e960dSAhmed S. Darwish #include <linux/capability.h> 9365e960dSAhmed S. Darwish #include <linux/pci.h> 10365e960dSAhmed S. Darwish #include <linux/sysfs.h> 11365e960dSAhmed S. Darwish 12*bcbb6555SIngo Molnar #include <asm/amd/nb.h> 13365e960dSAhmed S. Darwish 14365e960dSAhmed S. Darwish #include "cpu.h" 15365e960dSAhmed S. Darwish 16365e960dSAhmed S. Darwish /* 17365e960dSAhmed S. Darwish * L3 cache descriptors 18365e960dSAhmed S. Darwish */ 19365e960dSAhmed S. Darwish static void amd_calc_l3_indices(struct amd_northbridge *nb) 20365e960dSAhmed S. Darwish { 21365e960dSAhmed S. Darwish struct amd_l3_cache *l3 = &nb->l3_cache; 22365e960dSAhmed S. Darwish unsigned int sc0, sc1, sc2, sc3; 23365e960dSAhmed S. Darwish u32 val = 0; 24365e960dSAhmed S. Darwish 25365e960dSAhmed S. Darwish pci_read_config_dword(nb->misc, 0x1C4, &val); 26365e960dSAhmed S. Darwish 27365e960dSAhmed S. Darwish /* calculate subcache sizes */ 28365e960dSAhmed S. Darwish l3->subcaches[0] = sc0 = !(val & BIT(0)); 29365e960dSAhmed S. Darwish l3->subcaches[1] = sc1 = !(val & BIT(4)); 30365e960dSAhmed S. Darwish 31365e960dSAhmed S. Darwish if (boot_cpu_data.x86 == 0x15) { 32365e960dSAhmed S. Darwish l3->subcaches[0] = sc0 += !(val & BIT(1)); 33365e960dSAhmed S. Darwish l3->subcaches[1] = sc1 += !(val & BIT(5)); 34365e960dSAhmed S. Darwish } 35365e960dSAhmed S. Darwish 36365e960dSAhmed S. Darwish l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9)); 37365e960dSAhmed S. Darwish l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13)); 38365e960dSAhmed S. Darwish 39365e960dSAhmed S. Darwish l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1; 40365e960dSAhmed S. Darwish } 41365e960dSAhmed S. Darwish 42365e960dSAhmed S. Darwish /* 43365e960dSAhmed S. Darwish * check whether a slot used for disabling an L3 index is occupied. 44365e960dSAhmed S. Darwish * @l3: L3 cache descriptor 45365e960dSAhmed S. Darwish * @slot: slot number (0..1) 46365e960dSAhmed S. Darwish * 47365e960dSAhmed S. Darwish * @returns: the disabled index if used or negative value if slot free. 48365e960dSAhmed S. Darwish */ 49365e960dSAhmed S. Darwish static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned int slot) 50365e960dSAhmed S. Darwish { 51365e960dSAhmed S. Darwish unsigned int reg = 0; 52365e960dSAhmed S. Darwish 53365e960dSAhmed S. Darwish pci_read_config_dword(nb->misc, 0x1BC + slot * 4, ®); 54365e960dSAhmed S. Darwish 55365e960dSAhmed S. Darwish /* check whether this slot is activated already */ 56365e960dSAhmed S. Darwish if (reg & (3UL << 30)) 57365e960dSAhmed S. Darwish return reg & 0xfff; 58365e960dSAhmed S. Darwish 59365e960dSAhmed S. Darwish return -1; 60365e960dSAhmed S. Darwish } 61365e960dSAhmed S. Darwish 62365e960dSAhmed S. Darwish static ssize_t show_cache_disable(struct cacheinfo *ci, char *buf, unsigned int slot) 63365e960dSAhmed S. Darwish { 64365e960dSAhmed S. Darwish int index; 65365e960dSAhmed S. Darwish struct amd_northbridge *nb = ci->priv; 66365e960dSAhmed S. Darwish 67365e960dSAhmed S. Darwish index = amd_get_l3_disable_slot(nb, slot); 68365e960dSAhmed S. Darwish if (index >= 0) 69071f4ad6SAhmed S. Darwish return sysfs_emit(buf, "%d\n", index); 70365e960dSAhmed S. Darwish 71071f4ad6SAhmed S. Darwish return sysfs_emit(buf, "FREE\n"); 72365e960dSAhmed S. Darwish } 73365e960dSAhmed S. Darwish 74365e960dSAhmed S. Darwish #define SHOW_CACHE_DISABLE(slot) \ 75365e960dSAhmed S. Darwish static ssize_t \ 76365e960dSAhmed S. Darwish cache_disable_##slot##_show(struct device *dev, \ 77365e960dSAhmed S. Darwish struct device_attribute *attr, char *buf) \ 78365e960dSAhmed S. Darwish { \ 79365e960dSAhmed S. Darwish struct cacheinfo *ci = dev_get_drvdata(dev); \ 80365e960dSAhmed S. Darwish return show_cache_disable(ci, buf, slot); \ 81365e960dSAhmed S. Darwish } 82365e960dSAhmed S. Darwish 83365e960dSAhmed S. Darwish SHOW_CACHE_DISABLE(0) 84365e960dSAhmed S. Darwish SHOW_CACHE_DISABLE(1) 85365e960dSAhmed S. Darwish 86365e960dSAhmed S. Darwish static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu, 87365e960dSAhmed S. Darwish unsigned int slot, unsigned long idx) 88365e960dSAhmed S. Darwish { 89365e960dSAhmed S. Darwish int i; 90365e960dSAhmed S. Darwish 91365e960dSAhmed S. Darwish idx |= BIT(30); 92365e960dSAhmed S. Darwish 93365e960dSAhmed S. Darwish /* 94365e960dSAhmed S. Darwish * disable index in all 4 subcaches 95365e960dSAhmed S. Darwish */ 96365e960dSAhmed S. Darwish for (i = 0; i < 4; i++) { 97365e960dSAhmed S. Darwish u32 reg = idx | (i << 20); 98365e960dSAhmed S. Darwish 99365e960dSAhmed S. Darwish if (!nb->l3_cache.subcaches[i]) 100365e960dSAhmed S. Darwish continue; 101365e960dSAhmed S. Darwish 102365e960dSAhmed S. Darwish pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg); 103365e960dSAhmed S. Darwish 104365e960dSAhmed S. Darwish /* 105365e960dSAhmed S. Darwish * We need to WBINVD on a core on the node containing the L3 106365e960dSAhmed S. Darwish * cache which indices we disable therefore a simple wbinvd() 107365e960dSAhmed S. Darwish * is not sufficient. 108365e960dSAhmed S. Darwish */ 109365e960dSAhmed S. Darwish wbinvd_on_cpu(cpu); 110365e960dSAhmed S. Darwish 111365e960dSAhmed S. Darwish reg |= BIT(31); 112365e960dSAhmed S. Darwish pci_write_config_dword(nb->misc, 0x1BC + slot * 4, reg); 113365e960dSAhmed S. Darwish } 114365e960dSAhmed S. Darwish } 115365e960dSAhmed S. Darwish 116365e960dSAhmed S. Darwish /* 117365e960dSAhmed S. Darwish * disable a L3 cache index by using a disable-slot 118365e960dSAhmed S. Darwish * 119365e960dSAhmed S. Darwish * @l3: L3 cache descriptor 120365e960dSAhmed S. Darwish * @cpu: A CPU on the node containing the L3 cache 121365e960dSAhmed S. Darwish * @slot: slot number (0..1) 122365e960dSAhmed S. Darwish * @index: index to disable 123365e960dSAhmed S. Darwish * 124365e960dSAhmed S. Darwish * @return: 0 on success, error status on failure 125365e960dSAhmed S. Darwish */ 126365e960dSAhmed S. Darwish static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, 127365e960dSAhmed S. Darwish unsigned int slot, unsigned long index) 128365e960dSAhmed S. Darwish { 129365e960dSAhmed S. Darwish int ret = 0; 130365e960dSAhmed S. Darwish 131365e960dSAhmed S. Darwish /* check if @slot is already used or the index is already disabled */ 132365e960dSAhmed S. Darwish ret = amd_get_l3_disable_slot(nb, slot); 133365e960dSAhmed S. Darwish if (ret >= 0) 134365e960dSAhmed S. Darwish return -EEXIST; 135365e960dSAhmed S. Darwish 136365e960dSAhmed S. Darwish if (index > nb->l3_cache.indices) 137365e960dSAhmed S. Darwish return -EINVAL; 138365e960dSAhmed S. Darwish 139365e960dSAhmed S. Darwish /* check whether the other slot has disabled the same index already */ 140365e960dSAhmed S. Darwish if (index == amd_get_l3_disable_slot(nb, !slot)) 141365e960dSAhmed S. Darwish return -EEXIST; 142365e960dSAhmed S. Darwish 143365e960dSAhmed S. Darwish amd_l3_disable_index(nb, cpu, slot, index); 144365e960dSAhmed S. Darwish 145365e960dSAhmed S. Darwish return 0; 146365e960dSAhmed S. Darwish } 147365e960dSAhmed S. Darwish 148365e960dSAhmed S. Darwish static ssize_t store_cache_disable(struct cacheinfo *ci, const char *buf, 149365e960dSAhmed S. Darwish size_t count, unsigned int slot) 150365e960dSAhmed S. Darwish { 151365e960dSAhmed S. Darwish struct amd_northbridge *nb = ci->priv; 152365e960dSAhmed S. Darwish unsigned long val = 0; 153365e960dSAhmed S. Darwish int cpu, err = 0; 154365e960dSAhmed S. Darwish 155365e960dSAhmed S. Darwish if (!capable(CAP_SYS_ADMIN)) 156365e960dSAhmed S. Darwish return -EPERM; 157365e960dSAhmed S. Darwish 158365e960dSAhmed S. Darwish cpu = cpumask_first(&ci->shared_cpu_map); 159365e960dSAhmed S. Darwish 160365e960dSAhmed S. Darwish if (kstrtoul(buf, 10, &val) < 0) 161365e960dSAhmed S. Darwish return -EINVAL; 162365e960dSAhmed S. Darwish 163365e960dSAhmed S. Darwish err = amd_set_l3_disable_slot(nb, cpu, slot, val); 164365e960dSAhmed S. Darwish if (err) { 165365e960dSAhmed S. Darwish if (err == -EEXIST) 166365e960dSAhmed S. Darwish pr_warn("L3 slot %d in use/index already disabled!\n", 167365e960dSAhmed S. Darwish slot); 168365e960dSAhmed S. Darwish return err; 169365e960dSAhmed S. Darwish } 170365e960dSAhmed S. Darwish return count; 171365e960dSAhmed S. Darwish } 172365e960dSAhmed S. Darwish 173365e960dSAhmed S. Darwish #define STORE_CACHE_DISABLE(slot) \ 174365e960dSAhmed S. Darwish static ssize_t \ 175365e960dSAhmed S. Darwish cache_disable_##slot##_store(struct device *dev, \ 176365e960dSAhmed S. Darwish struct device_attribute *attr, \ 177365e960dSAhmed S. Darwish const char *buf, size_t count) \ 178365e960dSAhmed S. Darwish { \ 179365e960dSAhmed S. Darwish struct cacheinfo *ci = dev_get_drvdata(dev); \ 180365e960dSAhmed S. Darwish return store_cache_disable(ci, buf, count, slot); \ 181365e960dSAhmed S. Darwish } 182365e960dSAhmed S. Darwish 183365e960dSAhmed S. Darwish STORE_CACHE_DISABLE(0) 184365e960dSAhmed S. Darwish STORE_CACHE_DISABLE(1) 185365e960dSAhmed S. Darwish 186365e960dSAhmed S. Darwish static ssize_t subcaches_show(struct device *dev, struct device_attribute *attr, 187365e960dSAhmed S. Darwish char *buf) 188365e960dSAhmed S. Darwish { 189365e960dSAhmed S. Darwish struct cacheinfo *ci = dev_get_drvdata(dev); 190365e960dSAhmed S. Darwish int cpu = cpumask_first(&ci->shared_cpu_map); 191365e960dSAhmed S. Darwish 192071f4ad6SAhmed S. Darwish return sysfs_emit(buf, "%x\n", amd_get_subcaches(cpu)); 193365e960dSAhmed S. Darwish } 194365e960dSAhmed S. Darwish 195365e960dSAhmed S. Darwish static ssize_t subcaches_store(struct device *dev, 196365e960dSAhmed S. Darwish struct device_attribute *attr, 197365e960dSAhmed S. Darwish const char *buf, size_t count) 198365e960dSAhmed S. Darwish { 199365e960dSAhmed S. Darwish struct cacheinfo *ci = dev_get_drvdata(dev); 200365e960dSAhmed S. Darwish int cpu = cpumask_first(&ci->shared_cpu_map); 201365e960dSAhmed S. Darwish unsigned long val; 202365e960dSAhmed S. Darwish 203365e960dSAhmed S. Darwish if (!capable(CAP_SYS_ADMIN)) 204365e960dSAhmed S. Darwish return -EPERM; 205365e960dSAhmed S. Darwish 206365e960dSAhmed S. Darwish if (kstrtoul(buf, 16, &val) < 0) 207365e960dSAhmed S. Darwish return -EINVAL; 208365e960dSAhmed S. Darwish 209365e960dSAhmed S. Darwish if (amd_set_subcaches(cpu, val)) 210365e960dSAhmed S. Darwish return -EINVAL; 211365e960dSAhmed S. Darwish 212365e960dSAhmed S. Darwish return count; 213365e960dSAhmed S. Darwish } 214365e960dSAhmed S. Darwish 215365e960dSAhmed S. Darwish static DEVICE_ATTR_RW(cache_disable_0); 216365e960dSAhmed S. Darwish static DEVICE_ATTR_RW(cache_disable_1); 217365e960dSAhmed S. Darwish static DEVICE_ATTR_RW(subcaches); 218365e960dSAhmed S. Darwish 219365e960dSAhmed S. Darwish static umode_t cache_private_attrs_is_visible(struct kobject *kobj, 220365e960dSAhmed S. Darwish struct attribute *attr, int unused) 221365e960dSAhmed S. Darwish { 222365e960dSAhmed S. Darwish struct device *dev = kobj_to_dev(kobj); 223365e960dSAhmed S. Darwish struct cacheinfo *ci = dev_get_drvdata(dev); 224365e960dSAhmed S. Darwish umode_t mode = attr->mode; 225365e960dSAhmed S. Darwish 226365e960dSAhmed S. Darwish if (!ci->priv) 227365e960dSAhmed S. Darwish return 0; 228365e960dSAhmed S. Darwish 229365e960dSAhmed S. Darwish if ((attr == &dev_attr_subcaches.attr) && 230365e960dSAhmed S. Darwish amd_nb_has_feature(AMD_NB_L3_PARTITIONING)) 231365e960dSAhmed S. Darwish return mode; 232365e960dSAhmed S. Darwish 233365e960dSAhmed S. Darwish if ((attr == &dev_attr_cache_disable_0.attr || 234365e960dSAhmed S. Darwish attr == &dev_attr_cache_disable_1.attr) && 235365e960dSAhmed S. Darwish amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) 236365e960dSAhmed S. Darwish return mode; 237365e960dSAhmed S. Darwish 238365e960dSAhmed S. Darwish return 0; 239365e960dSAhmed S. Darwish } 240365e960dSAhmed S. Darwish 241365e960dSAhmed S. Darwish static struct attribute_group cache_private_group = { 242365e960dSAhmed S. Darwish .is_visible = cache_private_attrs_is_visible, 243365e960dSAhmed S. Darwish }; 244365e960dSAhmed S. Darwish 245365e960dSAhmed S. Darwish static void init_amd_l3_attrs(void) 246365e960dSAhmed S. Darwish { 247365e960dSAhmed S. Darwish static struct attribute **amd_l3_attrs; 248365e960dSAhmed S. Darwish int n = 1; 249365e960dSAhmed S. Darwish 250365e960dSAhmed S. Darwish if (amd_l3_attrs) /* already initialized */ 251365e960dSAhmed S. Darwish return; 252365e960dSAhmed S. Darwish 253365e960dSAhmed S. Darwish if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) 254365e960dSAhmed S. Darwish n += 2; 255365e960dSAhmed S. Darwish if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING)) 256365e960dSAhmed S. Darwish n += 1; 257365e960dSAhmed S. Darwish 258365e960dSAhmed S. Darwish amd_l3_attrs = kcalloc(n, sizeof(*amd_l3_attrs), GFP_KERNEL); 259365e960dSAhmed S. Darwish if (!amd_l3_attrs) 260365e960dSAhmed S. Darwish return; 261365e960dSAhmed S. Darwish 262365e960dSAhmed S. Darwish n = 0; 263365e960dSAhmed S. Darwish if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) { 264365e960dSAhmed S. Darwish amd_l3_attrs[n++] = &dev_attr_cache_disable_0.attr; 265365e960dSAhmed S. Darwish amd_l3_attrs[n++] = &dev_attr_cache_disable_1.attr; 266365e960dSAhmed S. Darwish } 267365e960dSAhmed S. Darwish if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING)) 268365e960dSAhmed S. Darwish amd_l3_attrs[n++] = &dev_attr_subcaches.attr; 269365e960dSAhmed S. Darwish 270365e960dSAhmed S. Darwish cache_private_group.attrs = amd_l3_attrs; 271365e960dSAhmed S. Darwish } 272365e960dSAhmed S. Darwish 273365e960dSAhmed S. Darwish const struct attribute_group *cache_get_priv_group(struct cacheinfo *ci) 274365e960dSAhmed S. Darwish { 275365e960dSAhmed S. Darwish struct amd_northbridge *nb = ci->priv; 276365e960dSAhmed S. Darwish 277365e960dSAhmed S. Darwish if (ci->level < 3 || !nb) 278365e960dSAhmed S. Darwish return NULL; 279365e960dSAhmed S. Darwish 280365e960dSAhmed S. Darwish if (nb && nb->l3_cache.indices) 281365e960dSAhmed S. Darwish init_amd_l3_attrs(); 282365e960dSAhmed S. Darwish 283365e960dSAhmed S. Darwish return &cache_private_group; 284365e960dSAhmed S. Darwish } 285365e960dSAhmed S. Darwish 286365e960dSAhmed S. Darwish struct amd_northbridge *amd_init_l3_cache(int index) 287365e960dSAhmed S. Darwish { 288365e960dSAhmed S. Darwish struct amd_northbridge *nb; 289365e960dSAhmed S. Darwish int node; 290365e960dSAhmed S. Darwish 291365e960dSAhmed S. Darwish /* only for L3, and not in virtualized environments */ 292365e960dSAhmed S. Darwish if (index < 3) 293365e960dSAhmed S. Darwish return NULL; 294365e960dSAhmed S. Darwish 295365e960dSAhmed S. Darwish node = topology_amd_node_id(smp_processor_id()); 296365e960dSAhmed S. Darwish nb = node_to_amd_nb(node); 297365e960dSAhmed S. Darwish if (nb && !nb->l3_cache.indices) 298365e960dSAhmed S. Darwish amd_calc_l3_indices(nb); 299365e960dSAhmed S. Darwish 300365e960dSAhmed S. Darwish return nb; 301365e960dSAhmed S. Darwish } 302