root/arch/x86/kernel/cpu/mtrr/legacy.c
// SPDX-License-Identifier: GPL-2.0-only

#include <linux/types.h>
#include <linux/slab.h>
#include <linux/syscore_ops.h>
#include <asm/cpufeature.h>
#include <asm/mtrr.h>
#include <asm/processor.h>
#include "mtrr.h"

void mtrr_set_if(void)
{
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_AMD:
                /* Pre-Athlon (K6) AMD CPU MTRRs */
                if (cpu_feature_enabled(X86_FEATURE_K6_MTRR))
                        mtrr_if = &amd_mtrr_ops;
                break;
        case X86_VENDOR_CENTAUR:
                if (cpu_feature_enabled(X86_FEATURE_CENTAUR_MCR))
                        mtrr_if = &centaur_mtrr_ops;
                break;
        case X86_VENDOR_CYRIX:
                if (cpu_feature_enabled(X86_FEATURE_CYRIX_ARR))
                        mtrr_if = &cyrix_mtrr_ops;
                break;
        default:
                break;
        }
}

/*
 * The suspend/resume methods are only for CPUs without MTRR. CPUs using generic
 * MTRR driver don't require this.
 */
struct mtrr_value {
        mtrr_type       ltype;
        unsigned long   lbase;
        unsigned long   lsize;
};

static struct mtrr_value *mtrr_value;

static int mtrr_save(void *data)
{
        int i;

        if (!mtrr_value)
                return -ENOMEM;

        for (i = 0; i < num_var_ranges; i++) {
                mtrr_if->get(i, &mtrr_value[i].lbase,
                                &mtrr_value[i].lsize,
                                &mtrr_value[i].ltype);
        }
        return 0;
}

static void mtrr_restore(void *data)
{
        int i;

        for (i = 0; i < num_var_ranges; i++) {
                if (mtrr_value[i].lsize) {
                        mtrr_if->set(i, mtrr_value[i].lbase,
                                     mtrr_value[i].lsize,
                                     mtrr_value[i].ltype);
                }
        }
}

static const struct syscore_ops mtrr_syscore_ops = {
        .suspend        = mtrr_save,
        .resume         = mtrr_restore,
};

static struct syscore mtrr_syscore = {
        .ops = &mtrr_syscore_ops,
};

void mtrr_register_syscore(void)
{
        mtrr_value = kzalloc_objs(*mtrr_value, num_var_ranges);

        /*
         * The CPU has no MTRR and seems to not support SMP. They have
         * specific drivers, we use a tricky method to support
         * suspend/resume for them.
         *
         * TBD: is there any system with such CPU which supports
         * suspend/resume? If no, we should remove the code.
         */
        register_syscore(&mtrr_syscore);
}