Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / x86 / kernel / amd_nb.c
index 0a99f71..6801959 100644 (file)
 
 static u32 *flush_words;
 
-struct pci_device_id amd_nb_misc_ids[] = {
+const struct pci_device_id amd_nb_misc_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
        {}
 };
 EXPORT_SYMBOL(amd_nb_misc_ids);
 
+static struct pci_device_id amd_nb_link_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_LINK) },
+       {}
+};
+
 const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {
        { 0x00, 0x18, 0x20 },
        { 0xff, 0x00, 0x20 },
@@ -31,7 +36,7 @@ struct amd_northbridge_info amd_northbridges;
 EXPORT_SYMBOL(amd_northbridges);
 
 static struct pci_dev *next_northbridge(struct pci_dev *dev,
-                                       struct pci_device_id *ids)
+                                       const struct pci_device_id *ids)
 {
        do {
                dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev);
@@ -43,9 +48,9 @@ static struct pci_dev *next_northbridge(struct pci_dev *dev,
 
 int amd_cache_northbridges(void)
 {
-       int i = 0;
+       u16 i = 0;
        struct amd_northbridge *nb;
-       struct pci_dev *misc;
+       struct pci_dev *misc, *link;
 
        if (amd_nb_num())
                return 0;
@@ -64,10 +69,12 @@ int amd_cache_northbridges(void)
        amd_northbridges.nb = nb;
        amd_northbridges.num = i;
 
-       misc = NULL;
+       link = misc = NULL;
        for (i = 0; i != amd_nb_num(); i++) {
                node_to_amd_nb(i)->misc = misc =
                        next_northbridge(misc, amd_nb_misc_ids);
+               node_to_amd_nb(i)->link = link =
+                       next_northbridge(link, amd_nb_link_ids);
         }
 
        /* some CPU families (e.g. family 0x11) do not support GART */
@@ -85,26 +92,95 @@ int amd_cache_northbridges(void)
             boot_cpu_data.x86_mask >= 0x1))
                amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
 
+       if (boot_cpu_data.x86 == 0x15)
+               amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE;
+
+       /* L3 cache partitioning is supported on family 0x15 */
+       if (boot_cpu_data.x86 == 0x15)
+               amd_northbridges.flags |= AMD_NB_L3_PARTITIONING;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(amd_cache_northbridges);
 
-/* Ignores subdevice/subvendor but as far as I can figure out
-   they're useless anyways */
-int __init early_is_amd_nb(u32 device)
+/*
+ * Ignores subdevice/subvendor but as far as I can figure out
+ * they're useless anyways
+ */
+bool __init early_is_amd_nb(u32 device)
 {
-       struct pci_device_id *id;
+       const struct pci_device_id *id;
        u32 vendor = device & 0xffff;
+
        device >>= 16;
        for (id = amd_nb_misc_ids; id->vendor; id++)
                if (vendor == id->vendor && device == id->device)
-                       return 1;
+                       return true;
+       return false;
+}
+
+int amd_get_subcaches(int cpu)
+{
+       struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link;
+       unsigned int mask;
+       int cuid = 0;
+
+       if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING))
+               return 0;
+
+       pci_read_config_dword(link, 0x1d4, &mask);
+
+#ifdef CONFIG_SMP
+       cuid = cpu_data(cpu).compute_unit_id;
+#endif
+       return (mask >> (4 * cuid)) & 0xf;
+}
+
+int amd_set_subcaches(int cpu, int mask)
+{
+       static unsigned int reset, ban;
+       struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu));
+       unsigned int reg;
+       int cuid = 0;
+
+       if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf)
+               return -EINVAL;
+
+       /* if necessary, collect reset state of L3 partitioning and BAN mode */
+       if (reset == 0) {
+               pci_read_config_dword(nb->link, 0x1d4, &reset);
+               pci_read_config_dword(nb->misc, 0x1b8, &ban);
+               ban &= 0x180000;
+       }
+
+       /* deactivate BAN mode if any subcaches are to be disabled */
+       if (mask != 0xf) {
+               pci_read_config_dword(nb->misc, 0x1b8, &reg);
+               pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000);
+       }
+
+#ifdef CONFIG_SMP
+       cuid = cpu_data(cpu).compute_unit_id;
+#endif
+       mask <<= 4 * cuid;
+       mask |= (0xf ^ (1 << cuid)) << 26;
+
+       pci_write_config_dword(nb->link, 0x1d4, mask);
+
+       /* reset BAN mode if L3 partitioning returned to reset state */
+       pci_read_config_dword(nb->link, 0x1d4, &reg);
+       if (reg == reset) {
+               pci_read_config_dword(nb->misc, 0x1b8, &reg);
+               reg &= ~0x180000;
+               pci_write_config_dword(nb->misc, 0x1b8, reg | ban);
+       }
+
        return 0;
 }
 
-int amd_cache_gart(void)
+static int amd_cache_gart(void)
 {
-       int i;
+       u16 i;
 
        if (!amd_nb_has_feature(AMD_NB_GART))
                return 0;