diff mbox series

[v2,02/10] x86/mtrr: remove unused cyrix_set_all() function

Message ID 20220820092533.29420-3-jgross@suse.com (mailing list archive)
State Superseded
Headers show
Series x86: make pat and mtrr independent from each other | expand

Commit Message

Jürgen Groß Aug. 20, 2022, 9:25 a.m. UTC
The Cyrix cpu specific MTRR function cyrix_set_all() will never be
called, as the struct mtrr_ops set_all() callback will only be called
in the use_intel() case, which would require the use_intel_if member
of struct mtrr_ops to be set, which isn't the case for Cyrix.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- new patch
---
 arch/x86/kernel/cpu/mtrr/cyrix.c | 34 --------------------------------
 1 file changed, 34 deletions(-)

Comments

Borislav Petkov Aug. 25, 2022, 10:31 a.m. UTC | #1
On Sat, Aug 20, 2022 at 11:25:25AM +0200, Juergen Gross wrote:
> The Cyrix cpu specific MTRR function cyrix_set_all() will never be
> called, as the struct mtrr_ops set_all() callback will only be called
> in the use_intel() case, which would require the use_intel_if member
> of struct mtrr_ops to be set, which isn't the case for Cyrix.

Doing some git archeology:

So the commit which added mtrr_aps_delayed_init is

  d0af9eed5aa9 ("x86, pat/mtrr: Rendezvous all the cpus for MTRR/PAT init")

from 2009.

The IPI callback before it, looked like this:

static void ipi_handler(void *info)
{
#ifdef CONFIG_SMP
	struct set_mtrr_data *data = info;
	unsigned long flags;

	local_irq_save(flags);

	atomic_dec(&data->count);
	while (!atomic_read(&data->gate))
		cpu_relax();

	/*  The master has cleared me to execute  */
	if (data->smp_reg != ~0U) {
		mtrr_if->set(data->smp_reg, data->smp_base,
			     data->smp_size, data->smp_type);
	} else {
		mtrr_if->set_all();
		^^^^^^^^^

and that else branch would call ->set_all() on Cyrix too.

Suresh's patch changed it to do:

-	} else {
+	} else if (mtrr_aps_delayed_init) {
+		/*
+		 * Initialize the MTRRs inaddition to the synchronisation.
+		 */
 		mtrr_if->set_all();

BUT below in the set_mtrr() call, it did:

        /*
         * HACK!
         * We use this same function to initialize the mtrrs on boot.
         * The state of the boot cpu's mtrrs has been saved, and we want
         * to replicate across all the APs.
         * If we're doing that @reg is set to something special...
         */
        if (reg != ~0U)
                mtrr_if->set(reg, base, size, type);
        else if (!mtrr_aps_delayed_init)
                mtrr_if->set_all();
		^^^

and that would be the Cyrix case.

But then

  192d8857427d ("x86, mtrr: use stop_machine APIs for doing MTRR rendezvous")

came and "cleaned" all up by removing the "HACK" and doing ->set_all()
only in the rendezvous handler:

+       } else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) {
                mtrr_if->set_all();
        }

Which begs the question: why doesn't the second part of the else test
match on Cyrix? The "|| !cpu_online(smp_processor_id())" case.

If only we had a Cyrix machine somewhere...
Jürgen Groß Aug. 25, 2022, 10:38 a.m. UTC | #2
On 25.08.22 12:31, Borislav Petkov wrote:
> On Sat, Aug 20, 2022 at 11:25:25AM +0200, Juergen Gross wrote:
>> The Cyrix cpu specific MTRR function cyrix_set_all() will never be
>> called, as the struct mtrr_ops set_all() callback will only be called
>> in the use_intel() case, which would require the use_intel_if member
>> of struct mtrr_ops to be set, which isn't the case for Cyrix.
> 
> Doing some git archeology:
> 
> So the commit which added mtrr_aps_delayed_init is
> 
>    d0af9eed5aa9 ("x86, pat/mtrr: Rendezvous all the cpus for MTRR/PAT init")
> 
> from 2009.
> 
> The IPI callback before it, looked like this:
> 
> static void ipi_handler(void *info)
> {
> #ifdef CONFIG_SMP
> 	struct set_mtrr_data *data = info;
> 	unsigned long flags;
> 
> 	local_irq_save(flags);
> 
> 	atomic_dec(&data->count);
> 	while (!atomic_read(&data->gate))
> 		cpu_relax();
> 
> 	/*  The master has cleared me to execute  */
> 	if (data->smp_reg != ~0U) {
> 		mtrr_if->set(data->smp_reg, data->smp_base,
> 			     data->smp_size, data->smp_type);
> 	} else {
> 		mtrr_if->set_all();
> 		^^^^^^^^^
> 
> and that else branch would call ->set_all() on Cyrix too.
> 
> Suresh's patch changed it to do:
> 
> -	} else {
> +	} else if (mtrr_aps_delayed_init) {
> +		/*
> +		 * Initialize the MTRRs inaddition to the synchronisation.
> +		 */
>   		mtrr_if->set_all();
> 
> BUT below in the set_mtrr() call, it did:
> 
>          /*
>           * HACK!
>           * We use this same function to initialize the mtrrs on boot.
>           * The state of the boot cpu's mtrrs has been saved, and we want
>           * to replicate across all the APs.
>           * If we're doing that @reg is set to something special...
>           */
>          if (reg != ~0U)
>                  mtrr_if->set(reg, base, size, type);
>          else if (!mtrr_aps_delayed_init)
>                  mtrr_if->set_all();
> 		^^^
> 
> and that would be the Cyrix case.
> 
> But then
> 
>    192d8857427d ("x86, mtrr: use stop_machine APIs for doing MTRR rendezvous")
> 
> came and "cleaned" all up by removing the "HACK" and doing ->set_all()
> only in the rendezvous handler:
> 
> +       } else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) {
>                  mtrr_if->set_all();
>          }
> 
> Which begs the question: why doesn't the second part of the else test
> match on Cyrix? The "|| !cpu_online(smp_processor_id())" case.
> 
> If only we had a Cyrix machine somewhere...
> 

You are missing one aspect here: there is no call path for Cyrix CPUs using
reg == ~0U.

So the condition of the "else if" will never be evaluated with Cyrix.


Juergen
Jürgen Groß Aug. 25, 2022, 10:41 a.m. UTC | #3
On 25.08.22 12:31, Borislav Petkov wrote:
> On Sat, Aug 20, 2022 at 11:25:25AM +0200, Juergen Gross wrote:
>> The Cyrix cpu specific MTRR function cyrix_set_all() will never be
>> called, as the struct mtrr_ops set_all() callback will only be called
>> in the use_intel() case, which would require the use_intel_if member
>> of struct mtrr_ops to be set, which isn't the case for Cyrix.
> 
> Doing some git archeology:
> 
> So the commit which added mtrr_aps_delayed_init is
> 
>    d0af9eed5aa9 ("x86, pat/mtrr: Rendezvous all the cpus for MTRR/PAT init")
> 
> from 2009.
> 
> The IPI callback before it, looked like this:
> 
> static void ipi_handler(void *info)
> {
> #ifdef CONFIG_SMP
> 	struct set_mtrr_data *data = info;
> 	unsigned long flags;
> 
> 	local_irq_save(flags);
> 
> 	atomic_dec(&data->count);
> 	while (!atomic_read(&data->gate))
> 		cpu_relax();
> 
> 	/*  The master has cleared me to execute  */
> 	if (data->smp_reg != ~0U) {
> 		mtrr_if->set(data->smp_reg, data->smp_base,
> 			     data->smp_size, data->smp_type);
> 	} else {
> 		mtrr_if->set_all();
> 		^^^^^^^^^
> 
> and that else branch would call ->set_all() on Cyrix too.
> 
> Suresh's patch changed it to do:
> 
> -	} else {
> +	} else if (mtrr_aps_delayed_init) {
> +		/*
> +		 * Initialize the MTRRs inaddition to the synchronisation.
> +		 */
>   		mtrr_if->set_all();
> 
> BUT below in the set_mtrr() call, it did:
> 
>          /*
>           * HACK!
>           * We use this same function to initialize the mtrrs on boot.
>           * The state of the boot cpu's mtrrs has been saved, and we want
>           * to replicate across all the APs.
>           * If we're doing that @reg is set to something special...
>           */
>          if (reg != ~0U)
>                  mtrr_if->set(reg, base, size, type);
>          else if (!mtrr_aps_delayed_init)
>                  mtrr_if->set_all();
> 		^^^
> 
> and that would be the Cyrix case.
> 
> But then
> 
>    192d8857427d ("x86, mtrr: use stop_machine APIs for doing MTRR rendezvous")
> 
> came and "cleaned" all up by removing the "HACK" and doing ->set_all()
> only in the rendezvous handler:
> 
> +       } else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) {
>                  mtrr_if->set_all();
>          }
> 
> Which begs the question: why doesn't the second part of the else test
> match on Cyrix? The "|| !cpu_online(smp_processor_id())" case.
> 
> If only we had a Cyrix machine somewhere...
> 

Maybe the alternative reasoning is much faster to understand: if the
Cyrix set_all() could be called, the AMD and Centaur ones would be callable,
too. Those being called would result in a NULL deref, so why should we keep
the Cyrix one?


Juergen
Borislav Petkov Aug. 25, 2022, 11:42 a.m. UTC | #4
On Thu, Aug 25, 2022 at 12:41:05PM +0200, Juergen Gross wrote:
> Maybe the alternative reasoning is much faster to understand: if the
> Cyrix set_all() could be called, the AMD and Centaur ones would be callable,
> too.

Right.

> Those being called would result in a NULL deref, so why should we keep
> the Cyrix one?

I know you're eager to remove dead code - I'd love that too. But before
we do that, we need to find out whether some Cyrix hw out there would
not need this.

I know, I know, they should've complained by now ... maybe they have but
we haven't heard about it.

What it most likely looks like is that those machines - a commit from
before git

commit 8fbdcb188e31ac901e216b466b97e90e8b057daa
Author: Dave Jones <davej@suse.de>
Date:   Wed Aug 14 21:14:22 2002 -0700

    [PATCH] Modular x86 MTRR driver.

talks about

+/*
+ * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
+ * with the SMM (System Management Mode) mode. So we need the following:
+ * Check whether SMI_LOCK (CCR3 bit 0) is set
+ *   if it is set, write a warning message: ARR3 cannot be changed!
+ *     (it cannot be changed until the next processor reset)

which sounds like old rust. And which no one uses or such machines are
long dead already.

Wikipedia says:

https://en.wikipedia.org/wiki/Cyrix_6x86

"The Cyrix 6x86 is a line of sixth-generation, 32-bit x86
microprocessors designed and released by Cyrix in 1995..."

So I'm thinking removing it would be ok...
Jürgen Groß Aug. 25, 2022, 12:13 p.m. UTC | #5
On 25.08.22 13:42, Borislav Petkov wrote:
> On Thu, Aug 25, 2022 at 12:41:05PM +0200, Juergen Gross wrote:
>> Maybe the alternative reasoning is much faster to understand: if the
>> Cyrix set_all() could be called, the AMD and Centaur ones would be callable,
>> too.
> 
> Right.
> 
>> Those being called would result in a NULL deref, so why should we keep
>> the Cyrix one?
> 
> I know you're eager to remove dead code - I'd love that too. But before
> we do that, we need to find out whether some Cyrix hw out there would
> not need this.

Back to reasoning #1. Only the use_intel() case calls the code in question
with reg == ~0. And use_intel() is clearly not Cyrix.


Juergen
diff mbox series

Patch

diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c
index ca670919b561..c77d3b0a5bf2 100644
--- a/arch/x86/kernel/cpu/mtrr/cyrix.c
+++ b/arch/x86/kernel/cpu/mtrr/cyrix.c
@@ -234,42 +234,8 @@  static void cyrix_set_arr(unsigned int reg, unsigned long base,
 	post_set();
 }
 
-typedef struct {
-	unsigned long	base;
-	unsigned long	size;
-	mtrr_type	type;
-} arr_state_t;
-
-static arr_state_t arr_state[8] = {
-	{0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL},
-	{0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}, {0UL, 0UL, 0UL}
-};
-
-static unsigned char ccr_state[7] = { 0, 0, 0, 0, 0, 0, 0 };
-
-static void cyrix_set_all(void)
-{
-	int i;
-
-	prepare_set();
-
-	/* the CCRs are not contiguous */
-	for (i = 0; i < 4; i++)
-		setCx86(CX86_CCR0 + i, ccr_state[i]);
-	for (; i < 7; i++)
-		setCx86(CX86_CCR4 + i, ccr_state[i]);
-
-	for (i = 0; i < 8; i++) {
-		cyrix_set_arr(i, arr_state[i].base,
-			      arr_state[i].size, arr_state[i].type);
-	}
-
-	post_set();
-}
-
 static const struct mtrr_ops cyrix_mtrr_ops = {
 	.vendor            = X86_VENDOR_CYRIX,
-	.set_all	   = cyrix_set_all,
 	.set               = cyrix_set_arr,
 	.get               = cyrix_get_arr,
 	.get_free_region   = cyrix_get_free_region,