All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
To: "H. Peter Anvin" <hpa@zytor.com>
Cc: Matt Mackall <mpm@selenic.com>,
	Linux-tiny@selenic.com, Andrew Morton <akpm@linux-foundation.org>,
	linux-kernel@vger.kernel.org, Ingo Molnar <mingo@elte.hu>,
	Thomas Gleixner <tglx@linutronix.de>
Subject: [RFC] [PATCH] x86: Use ELF section to list CPU vendor specific code (Linux Tiny)
Date: Fri, 15 Feb 2008 12:00:23 +0100	[thread overview]
Message-ID: <20080215120023.252647bd@crazy> (raw)
In-Reply-To: <47B0EE46.6050208@zytor.com>

[-- Attachment #1: Type: text/plain, Size: 10558 bytes --]

Hi,

Le Mon, 11 Feb 2008 16:54:30 -0800,
"H. Peter Anvin" <hpa@zytor.com> a écrit :

> b) would be my first choice, and yes, it would be a good thing to
> have a generalized mechanism for this.  For the registrant, it's
> pretty easy: just add a macro that adds a pointer to a named
> section.  We then need a way to get the base address and length of
> each such section in order to be able to execute each function in
> sequence.

You'll find below a tentative patch that implements this. Tuple
(vendor, pointer to cpu_dev structure) are stored in a
x86cpuvendor.init section of the kernel, which is then read by the
generic CPU code in arch/x86/kernel/cpu/common.c to fill the cpu_devs[]
function.

Moreover the early_init_...() calls are integrated into that mechanism
using a new c_early_init() member of the cpu_dev structure.

The patch is for review only at the moment. Disabling compilation of
unused CPU support code will be done in a separate patch (I've taken
over Michael Opdenacker's work for the moment, with his agreement).

Thanks for your review and comments,

Thomas

---

Replace the hardcoded list of initialization functions for each CPU
vendor by a list in an ELF section, which is read at initialization in
arch/x86/kernel/cpu/cpu.c to fill the cpu_devs[] array. The ELF
section, named .x86cpuvendor.init, is reclaimed after boot, and
contains entries of type "struct cpu_vendor_dev" which associates a
vendor number with a pointer to a "struct cpu_dev" structure.

This first modification allows to remove all the VENDOR_init_cpu()
functions.

This patch also removes the hardcoded calls to early_init_amd() and
early_init_intel(). Instead, we add a "c_early_init" member to the
cpu_dev structure, which is then called if not NULL by the generic CPU
initialization code. Unfortunately, in early_cpu_detect(), this_cpu is
not yet set, so we have to use the cpu_devs[] array directly.

This patch is part of the Linux Tiny project, and is needed for
further patch that will allow to disable compilation of unused CPU
support code.

Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>

---
 arch/x86/kernel/cpu/amd.c        |    5 ++++-
 arch/x86/kernel/cpu/centaur.c    |    6 +-----
 arch/x86/kernel/cpu/common.c     |   33 ++++++++++-----------------------
 arch/x86/kernel/cpu/cpu.h        |   26 +++++++++++++-------------
 arch/x86/kernel/cpu/cyrix.c      |   13 ++-----------
 arch/x86/kernel/cpu/intel.c      |    9 +++------
 arch/x86/kernel/cpu/transmeta.c  |    6 +-----
 arch/x86/kernel/cpu/umc.c        |    7 ++-----
 arch/x86/kernel/vmlinux_32.lds.S |    5 +++++
 arch/x86/kernel/vmlinux_64.lds.S |    5 +++++
 10 files changed, 46 insertions(+), 69 deletions(-)

Index: linux/arch/x86/kernel/cpu/amd.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/amd.c
+++ linux/arch/x86/kernel/cpu/amd.c
@@ -63,7 +63,7 @@
 
 int force_mwait __cpuinitdata;
 
-void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
+static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
 {
 	if (cpuid_eax(0x80000000) >= 0x80000007) {
 		c->x86_power = cpuid_edx(0x80000007);
@@ -336,6 +336,7 @@
 		  }
 		},
 	},
+	.c_early_init   = early_init_amd,
 	.c_init		= init_amd,
 	.c_size_cache	= amd_size_cache,
 };
@@ -345,3 +346,5 @@
 	cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev;
 	return 0;
 }
+
+cpu_vendor_dev_register(X86_VENDOR_AMD, &amd_cpu_dev);
Index: linux/arch/x86/kernel/cpu/centaur.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/centaur.c
+++ linux/arch/x86/kernel/cpu/centaur.c
@@ -464,8 +464,4 @@
 	.c_size_cache	= centaur_size_cache,
 };
 
-int __init centaur_init_cpu(void)
-{
-	cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
-	return 0;
-}
+cpu_vendor_dev_register(X86_VENDOR_CENTAUR, &centaur_cpu_dev);
Index: linux/arch/x86/kernel/cpu/common.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/common.c
+++ linux/arch/x86/kernel/cpu/common.c
@@ -328,14 +328,9 @@
 
 	get_cpu_vendor(c, 1);
 
-	switch (c->x86_vendor) {
-	case X86_VENDOR_AMD:
-		early_init_amd(c);
-		break;
-	case X86_VENDOR_INTEL:
-		early_init_intel(c);
-		break;
-	}
+	if (c->x86_vendor != X86_VENDOR_UNKNOWN &&
+	    cpu_devs[c->x86_vendor]->c_early_init)
+		cpu_devs[c->x86_vendor]->c_early_init(c);
 
 	early_get_cap(c);
 }
@@ -616,23 +611,15 @@
 
 cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
 
-/* This is hacky. :)
- * We're emulating future behavior.
- * In the future, the cpu-specific init functions will be called implicitly
- * via the magic of initcalls.
- * They will insert themselves into the cpu_devs structure.
- * Then, when cpu_init() is called, we can just iterate over that array.
- */
 void __init early_cpu_init(void)
 {
-	intel_cpu_init();
-	cyrix_init_cpu();
-	nsc_init_cpu();
-	amd_init_cpu();
-	centaur_init_cpu();
-	transmeta_init_cpu();
-	nexgen_init_cpu();
-	umc_init_cpu();
+	struct cpu_vendor_dev *cvdev;
+
+	for (cvdev = __x86cpuvendor_start ;
+	     cvdev < __x86cpuvendor_end   ;
+	     cvdev++)
+		cpu_devs[cvdev->vendor] = cvdev->cpu_dev;
+
 	early_cpu_detect();
 }
 
Index: linux/arch/x86/kernel/cpu/cpu.h
===================================================================
--- linux.orig/arch/x86/kernel/cpu/cpu.h
+++ linux/arch/x86/kernel/cpu/cpu.h
@@ -14,6 +14,7 @@
 
 	struct		cpu_model_info c_models[4];
 
+	void            (*c_early_init)(struct cpuinfo_x86 *c);
 	void		(*c_init)(struct cpuinfo_x86 * c);
 	void		(*c_identify)(struct cpuinfo_x86 * c);
 	unsigned int	(*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
@@ -21,18 +22,17 @@
 
 extern struct cpu_dev * cpu_devs [X86_VENDOR_NUM];
 
-extern int get_model_name(struct cpuinfo_x86 *c);
-extern void display_cacheinfo(struct cpuinfo_x86 *c);
+struct cpu_vendor_dev {
+	int vendor;
+	struct cpu_dev *cpu_dev;
+};
 
-extern void early_init_intel(struct cpuinfo_x86 *c);
-extern void early_init_amd(struct cpuinfo_x86 *c);
+#define cpu_vendor_dev_register(cpu_vendor_id, cpu_dev) \
+	static struct cpu_vendor_dev __cpu_vendor_dev_##cpu_vendor_id __used \
+	__attribute__((__section__(".x86cpuvendor.init"))) = \
+	{ cpu_vendor_id, cpu_dev }
 
-/* Specific CPU type init functions */
-int intel_cpu_init(void);
-int amd_init_cpu(void);
-int cyrix_init_cpu(void);
-int nsc_init_cpu(void);
-int centaur_init_cpu(void);
-int transmeta_init_cpu(void);
-int nexgen_init_cpu(void);
-int umc_init_cpu(void);
+extern struct cpu_vendor_dev __x86cpuvendor_start[], __x86cpuvendor_end[];
+
+extern int get_model_name(struct cpuinfo_x86 *c);
+extern void display_cacheinfo(struct cpuinfo_x86 *c);
Index: linux/arch/x86/kernel/cpu/cyrix.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/cyrix.c
+++ linux/arch/x86/kernel/cpu/cyrix.c
@@ -439,11 +439,7 @@
 	.c_identify	= cyrix_identify,
 };
 
-int __init cyrix_init_cpu(void)
-{
-	cpu_devs[X86_VENDOR_CYRIX] = &cyrix_cpu_dev;
-	return 0;
-}
+cpu_vendor_dev_register(X86_VENDOR_CYRIX, &cyrix_cpu_dev);
 
 static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
 	.c_vendor	= "NSC",
@@ -451,9 +447,4 @@
 	.c_init		= init_nsc,
 };
 
-int __init nsc_init_cpu(void)
-{
-	cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev;
-	return 0;
-}
-
+cpu_vendor_dev_register(X86_VENDOR_NSC, &nsc_cpu_dev);
Index: linux/arch/x86/kernel/cpu/intel.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/intel.c
+++ linux/arch/x86/kernel/cpu/intel.c
@@ -30,7 +30,7 @@
 struct movsl_mask movsl_mask __read_mostly;
 #endif
 
-void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
+static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
 {
 	/* Netburst reports 64 bytes clflush size, but does IO in 128 bytes */
 	if (c->x86 == 15 && c->x86_cache_alignment == 64)
@@ -290,15 +290,12 @@
 		  }
 		},
 	},
+	.c_early_init   = early_init_intel,
 	.c_init		= init_intel,
 	.c_size_cache	= intel_size_cache,
 };
 
-__init int intel_cpu_init(void)
-{
-	cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev;
-	return 0;
-}
+cpu_vendor_dev_register(X86_VENDOR_INTEL, &intel_cpu_dev);
 
 #ifndef CONFIG_X86_CMPXCHG
 unsigned long cmpxchg_386_u8(volatile void *ptr, u8 old, u8 new)
Index: linux/arch/x86/kernel/cpu/transmeta.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/transmeta.c
+++ linux/arch/x86/kernel/cpu/transmeta.c
@@ -109,8 +109,4 @@
 	.c_identify	= transmeta_identify,
 };
 
-int __init transmeta_init_cpu(void)
-{
-	cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
-	return 0;
-}
+cpu_vendor_dev_register(X86_VENDOR_TRANSMETA, &transmeta_cpu_dev);
Index: linux/arch/x86/kernel/cpu/umc.c
===================================================================
--- linux.orig/arch/x86/kernel/cpu/umc.c
+++ linux/arch/x86/kernel/cpu/umc.c
@@ -19,8 +19,5 @@
 	},
 };
 
-int __init umc_init_cpu(void)
-{
-	cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev;
-	return 0;
-}
+cpu_vendor_dev_register(X86_VENDOR_UMC, &umc_cpu_dev);
+
Index: linux/arch/x86/kernel/vmlinux_32.lds.S
===================================================================
--- linux.orig/arch/x86/kernel/vmlinux_32.lds.S
+++ linux/arch/x86/kernel/vmlinux_32.lds.S
@@ -149,6 +149,11 @@
 	*(.con_initcall.init)
   	__con_initcall_end = .;
   }
+  .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
+	__x86cpuvendor_start = .;
+	*(.x86cpuvendor.init)
+	__x86cpuvendor_end = .;
+  }
   SECURITY_INIT
   . = ALIGN(4);
   .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
Index: linux/arch/x86/kernel/vmlinux_64.lds.S
===================================================================
--- linux.orig/arch/x86/kernel/vmlinux_64.lds.S
+++ linux/arch/x86/kernel/vmlinux_64.lds.S
@@ -177,6 +177,11 @@
 	*(.con_initcall.init)
   }
   __con_initcall_end = .;
+  __x86cpuvendor_start = .;
+  .x86cpuvendor.init : AT(ADDR(.x86cpuvendor.init) - LOAD_OFFSET) {
+	*(.x86cpuvendor.init)
+  }
+  __x86cpuvendor_end = .;
   SECURITY_INIT
 
   . = ALIGN(8);


-- 
Thomas Petazzoni, Free Electrons
Free Embedded Linux Training Materials
on http://free-electrons.com/training
(More than 1500 pages!)

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

  parent reply	other threads:[~2008-02-15 11:00 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-02-08 22:47 [PATCH] x86 (Linux Tiny): configure out support for some processors Michael Opdenacker
2008-02-08 23:04 ` H. Peter Anvin
2008-02-08 23:11 ` Ingo Molnar
2008-02-09  9:31   ` Michael Opdenacker
2008-02-11 22:42   ` Michael Opdenacker
2008-02-11 22:56     ` Matt Mackall
2008-02-11 23:01       ` H. Peter Anvin
2008-02-11 23:28         ` Matt Mackall
2008-02-12  0:54           ` H. Peter Anvin
2008-02-12  1:15             ` Matt Mackall
2008-02-15 11:00             ` Thomas Petazzoni [this message]
2008-02-17 18:14               ` [RFC] [PATCH] x86: Use ELF section to list CPU vendor specific code (Linux Tiny) Ingo Molnar
2008-02-17 19:46                 ` H. Peter Anvin
2008-02-23  2:43               ` Matt Mackall
2008-02-23  3:19                 ` H. Peter Anvin
2008-02-25  8:29                 ` Thomas Petazzoni
2008-02-25 17:03                   ` Matt Mackall
2008-02-25 17:53                     ` Thomas Petazzoni
2008-02-25 17:58                       ` Matt Mackall
2008-02-11 22:59     ` [PATCH] x86 (Linux Tiny): configure out support for some processors H. Peter Anvin
2008-02-08 23:20 ` Matt Mackall
2008-02-09  8:30   ` Simon Holm Thøgersen
2008-02-09  9:29     ` Michael Opdenacker
2008-02-09 10:05       ` Simon Holm Thøgersen
2008-02-09 21:35       ` H. Peter Anvin
2008-02-09  9:26   ` Michael Opdenacker
2008-02-09  3:48 ` Taral

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080215120023.252647bd@crazy \
    --to=thomas.petazzoni@free-electrons.com \
    --cc=Linux-tiny@selenic.com \
    --cc=akpm@linux-foundation.org \
    --cc=hpa@zytor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=mpm@selenic.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.