Support HWCAPs for MIPS

Message ID 6D39441BF12EF246A7ABCE6654B0235320F271C0@LEMAIL01.le.imgtec.org
State Deferred, archived
Headers

Commit Message

Matthew Fortune Oct. 14, 2014, 9:51 p.m. UTC
  This patch is split out of
https://sourceware.org/ml/libc-alpha/2014-10/msg00056.html

MIPS is beginning to use HWCAPs and initially R6 and MSA feature bits
are being defined. The MSA bit will be used by the O32 FPXX ABI
patch. The R6 bit is to support runtime code generation by JITs so
that they can avoid trap and emulation of removed instructions in
generated code. (A patch to enable GLIBC to be built for R6 will
be submitted in due course so that the optimised assembly routines
also avoid removed instructions.)

Thanks,
Matthew

	* sysdeps/mips/bits/hwcap.h: New file.
	* sysdeps/mips/dl-procinfo.c (_dl_mips_cap_flags): Declare.
	* sysdeps/mips/dl-procinfo.h (_DL_HWCAP_COUNT): Define.
	(HWCAP_IMPORTANT): Define.
	(_dl_procinfo): New static inline function.
	(_dl_hwcap_string, _dl_string_hwcap): Likewise.
---
 sysdeps/mips/bits/hwcap.h  | 24 ++++++++++++++++++++++
 sysdeps/mips/dl-procinfo.c | 16 +++++++++++++++
 sysdeps/mips/dl-procinfo.h | 50 +++++++++++++++++++++++++++++++++++++---------
 3 files changed, 81 insertions(+), 9 deletions(-)
 create mode 100644 sysdeps/mips/bits/hwcap.h
  

Comments

Joseph Myers Oct. 14, 2014, 11:13 p.m. UTC | #1
On Tue, 14 Oct 2014, Matthew Fortune wrote:

> +#define HWCAP_MIPS_R6	0x00000001
> +#define HWCAP_MIPS_MSA	0x00000002

HWCAP values are assigned by the kernel; they are not ELF-level interfaces 
but interfaces between the kernel and userspace; we normally add new 
values once there's been a kernel.org release with those values in, as 
part of the routine review of new kernel releases for any new interfaces 
of relevance to glibc.  In this case, I don't see these values in 
kernel.org git at all, so it seems premature to add them to glibc; please 
resubmit this patch once the values have been assigned in the kernel (or 
if one value is assigned before the other, it's fine to submit a patch 
with just that value as soon as it's been assigned).

If I've missed the definition of these values in the kernel, please give 
more details of where they are defined 
(git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git rather 
than any other, e.g. architecture-specific, git tree).

Being Linux-specific, I think the right location for these files is 
sysdeps/unix/sysv/linux/mips/ similar to ARM (although other architectures 
putting such OS-specific definitions in OS-independent files doesn't cause 
practical problems in the absence of other-OS ports for those 
architectures).

If you want to get other patches depending on HWCAP tests in some way into 
glibc before the HWCAP values are allocated in the kernel, I advise 
setting up the glibc code to hardcode whatever it would do with an old 
kernel that never sets a nonzero HWCAP, and then adding support for 
handling new kernel features later when the values are allocated.
  
Matthew Fortune Oct. 15, 2014, 6:20 p.m. UTC | #2
Joseph S. Myers <joseph@codesourcery.com> writes
> On Tue, 14 Oct 2014, Matthew Fortune wrote:
> 
> > +#define HWCAP_MIPS_R6	0x00000001
> > +#define HWCAP_MIPS_MSA	0x00000002
> 
> HWCAP values are assigned by the kernel; they are not ELF-level interfaces
> but interfaces between the kernel and userspace; we normally add new
> values once there's been a kernel.org release with those values in, as
> part of the routine review of new kernel releases for any new interfaces
> of relevance to glibc.  In this case, I don't see these values in

For architecture independent interfaces/extensions I completely agree as it
is not possible to predict what values will be assigned. In this case we
have a spec which the kernel and glibc can follow for MIPS. I'm not sure I
see the need to wait for the kernel changes to hit the main kernel repo.

I.e. if we had agreement on a spec between an architecture maintainer for
the kernel and glibc then that would seem sufficient.

> Being Linux-specific, I think the right location for these files is
> sysdeps/unix/sysv/linux/mips/ similar to ARM (although other architectures
> putting such OS-specific definitions in OS-independent files doesn't cause
> practical problems in the absence of other-OS ports for those
> architectures).

OK.
 
> If you want to get other patches depending on HWCAP tests in some way into
> glibc before the HWCAP values are allocated in the kernel, I advise
> setting up the glibc code to hardcode whatever it would do with an old
> kernel that never sets a nonzero HWCAP, and then adding support for
> handling new kernel features later when the values are allocated.

Given the current approach is to wait for changes to hit the kernel I'll
skip this for now and hard-code as suggested.

Thanks,
Matthew
  
Joseph Myers Oct. 15, 2014, 7:01 p.m. UTC | #3
On Wed, 15 Oct 2014, Matthew Fortune wrote:

> For architecture independent interfaces/extensions I completely agree as it
> is not possible to predict what values will be assigned. In this case we
> have a spec which the kernel and glibc can follow for MIPS. I'm not sure I
> see the need to wait for the kernel changes to hit the main kernel repo.
> 
> I.e. if we had agreement on a spec between an architecture maintainer for
> the kernel and glibc then that would seem sufficient.

I don't think it's wise to assume that these particular values will be the 
first ones getting into the kernel, rather than someone else deciding to 
implement some other HWCAP values on MIPS and getting those in first (and 
thereby taking the first available values, which is the natural choice).  
Cf. cases where people have had out-of-tree patches for socket 
address/protocol families and have had to change the numbers assigned 
because of others going in the kernel and taking those values.

If the values get in the kernel quickly, there isn't much delay in glibc.  
If they take as long to get in the kernel as NaN2008 support (where more 
than a year after glibc support went in, glibc built for NaN2008 still 
uses arch_minimum_kernel=10.0.0 because the kernel support still hasn't 
gone in), that's a very long time to hope that no-one else gets in some 
other MIPS HWCAP values.

I've no idea if you can persuade kernel people of the merits of defining a 
value in a kernel header to fix the ABI even if the actual implementation 
follows later (cf. the O_* discussions, though I think the conclusion 
there ended up being that the kernel should implement the actual semantics 
rather than just reserving values for userspace implementation).
  
Mike Frysinger March 6, 2015, 11:38 a.m. UTC | #4
On 14 Oct 2014 21:51, Matthew Fortune wrote:
> +static inline int
> +__attribute__ ((unused))
> +_dl_procinfo (unsigned int type, unsigned long int word)

i think we just use "unsigned long".  pairing "int" with "long" is just a waste 
of space.

> +{
> +  int i;
> +
> +  /* Fallback to unknown output mechanism.  */
> +  if (type == AT_HWCAP2)
> +    return -1;
> +
> +  _dl_printf ("AT_HWCAP:   ");
> +
> +  for (i = 0; i < _DL_HWCAP_COUNT; ++i)
> +    if (word & (1 << i))

i is an int, but word is an unsigned long int.  probably want to harmonize those 
types.

> +static inline const char *
> +__attribute__ ((unused))
> +_dl_hwcap_string (int idx)
> +{
> +  return GLRO(dl_mips_cap_flags)[idx];
> +};

no trailing semi-colons on func defs

> +static inline int
> +__attribute__ ((unused))
> +_dl_string_hwcap (const char *str)
> +{
> +  int i;
>  
> -#define _dl_string_hwcap(str) (-1)
> +  for (i = 0; i < _DL_HWCAP_COUNT; i++)

nit: ++i

> +    {
> +      if (strcmp (str, GLRO(dl_mips_cap_flags)[i]) == 0)
> +	return i;
> +    }

no need for the braces

> +  return -1;

GNU style says to put a blank line above the return

> +};

no trailing semi-colons on func defs
-mike
  
Andreas Schwab March 6, 2015, 3:52 p.m. UTC | #5
Mike Frysinger <vapier@gentoo.org> writes:

>> +{
>> +  int i;
>> +
>> +  /* Fallback to unknown output mechanism.  */
>> +  if (type == AT_HWCAP2)
>> +    return -1;
>> +
>> +  _dl_printf ("AT_HWCAP:   ");
>> +
>> +  for (i = 0; i < _DL_HWCAP_COUNT; ++i)
>> +    if (word & (1 << i))
>
> i is an int, but word is an unsigned long int.

That's not a problem.  The problem is that 1 is an int.

Andreas.
  
Carlos O'Donell March 6, 2015, 3:57 p.m. UTC | #6
On 03/06/2015 10:52 AM, Andreas Schwab wrote:
> Mike Frysinger <vapier@gentoo.org> writes:
> 
>>> +{
>>> +  int i;
>>> +
>>> +  /* Fallback to unknown output mechanism.  */
>>> +  if (type == AT_HWCAP2)
>>> +    return -1;
>>> +
>>> +  _dl_printf ("AT_HWCAP:   ");
>>> +
>>> +  for (i = 0; i < _DL_HWCAP_COUNT; ++i)
>>> +    if (word & (1 << i))
>>
>> i is an int, but word is an unsigned long int.
> 
> That's not a problem.  The problem is that 1 is an int.

Right, you want 1U.

Which reminds me that elf.h is all wrong also and needs 1U everywhere.

Cheers,
Carlos.
  
Matthew Fortune March 6, 2015, 4:44 p.m. UTC | #7
Carlos O'Donell <carlos@redhat.com> writes:
> On 03/06/2015 10:52 AM, Andreas Schwab wrote:
> > Mike Frysinger <vapier@gentoo.org> writes:
> >
> >>> +{
> >>> +  int i;
> >>> +
> >>> +  /* Fallback to unknown output mechanism.  */  if (type ==
> >>> + AT_HWCAP2)
> >>> +    return -1;
> >>> +
> >>> +  _dl_printf ("AT_HWCAP:   ");
> >>> +
> >>> +  for (i = 0; i < _DL_HWCAP_COUNT; ++i)
> >>> +    if (word & (1 << i))
> >>
> >> i is an int, but word is an unsigned long int.
> >
> > That's not a problem.  The problem is that 1 is an int.
> 
> Right, you want 1U.
> 
> Which reminds me that elf.h is all wrong also and needs 1U everywhere.

Thanks Mike for the review. I admit to blindly stealing this from
another port in glibc (I don't recall which). Since I still haven't
managed to get any HWCAPs into mainline kernel then I was just going
to wait until I had a HWCAP to include before pushing ahead with
this.

Should I update this and get the framework committed while waiting for
things to trickle in to the kernel?

Thanks,
Matthew
  
Andreas Schwab March 6, 2015, 4:46 p.m. UTC | #8
"Carlos O'Donell" <carlos@redhat.com> writes:

> On 03/06/2015 10:52 AM, Andreas Schwab wrote:
>> Mike Frysinger <vapier@gentoo.org> writes:
>> 
>>>> +{
>>>> +  int i;
>>>> +
>>>> +  /* Fallback to unknown output mechanism.  */
>>>> +  if (type == AT_HWCAP2)
>>>> +    return -1;
>>>> +
>>>> +  _dl_printf ("AT_HWCAP:   ");
>>>> +
>>>> +  for (i = 0; i < _DL_HWCAP_COUNT; ++i)
>>>> +    if (word & (1 << i))
>>>
>>> i is an int, but word is an unsigned long int.
>> 
>> That's not a problem.  The problem is that 1 is an int.
>
> Right, you want 1U.

unsigned int is still a problem.

Andreas.
  
Joseph Myers Nov. 17, 2015, 5:08 p.m. UTC | #9
Now that the initial HWCAPs are in Linux 4.3, will you be resubmitting 
HWCAP support for MIPS?
  

Patch

diff --git a/sysdeps/mips/bits/hwcap.h b/sysdeps/mips/bits/hwcap.h
new file mode 100644
index 0000000..0013717
--- /dev/null
+++ b/sysdeps/mips/bits/hwcap.h
@@ -0,0 +1,24 @@ 
+/* Defines for bits in AT_HWCAP.
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#if !defined(_SYS_AUXV_H) && !defined(_SYSDEPS_SYSDEP_H)
+# error "Never include <bits/hwcap.h> directly; use <sys/auxv.h> instead."
+#endif
+
+#define HWCAP_MIPS_R6	0x00000001
+#define HWCAP_MIPS_MSA	0x00000002
diff --git a/sysdeps/mips/dl-procinfo.c b/sysdeps/mips/dl-procinfo.c
index 4a3dbf3..3e7b7ed 100644
--- a/sysdeps/mips/dl-procinfo.c
+++ b/sysdeps/mips/dl-procinfo.c
@@ -59,5 +59,21 @@  PROCINFO_CLASS const char _dl_mips_platforms[4][11]
 ,
 #endif
 
+#if !defined PROCINFO_DECL && defined SHARED
+  ._dl_mips_cap_flags
+#else
+PROCINFO_CLASS const char _dl_mips_cap_flags[2][4]
+#endif
+#ifndef PROCINFO_DECL
+= {
+    "r6", "msa"
+  }
+#endif
+#if !defined SHARED || defined PROCINFO_DECL
+;
+#else
+,
+#endif
+
 #undef PROCINFO_DECL
 #undef PROCINFO_CLASS
diff --git a/sysdeps/mips/dl-procinfo.h b/sysdeps/mips/dl-procinfo.h
index b2b7702..3aa236a 100644
--- a/sysdeps/mips/dl-procinfo.h
+++ b/sysdeps/mips/dl-procinfo.h
@@ -50,18 +50,50 @@  _dl_string_platform (const char *str)
   return -1;
 };
 
-/* We cannot provide a general printing function.  */
-#define _dl_procinfo(type, word) -1
+#define _DL_HWCAP_COUNT	2
 
-/* There are no hardware capabilities defined.  */
-#define _dl_hwcap_string(idx) ""
+#define HWCAP_IMPORTANT	(HWCAP_MIPS_MSA)
 
-/* By default there is no important hardware capability.  */
-#define HWCAP_IMPORTANT (0)
+static inline int
+__attribute__ ((unused))
+_dl_procinfo (unsigned int type, unsigned long int word)
+{
+  int i;
+
+  /* Fallback to unknown output mechanism.  */
+  if (type == AT_HWCAP2)
+    return -1;
+
+  _dl_printf ("AT_HWCAP:   ");
+
+  for (i = 0; i < _DL_HWCAP_COUNT; ++i)
+    if (word & (1 << i))
+      _dl_printf (" %s", GLRO(dl_mips_cap_flags)[i]);
+
+  _dl_printf ("\n");
+
+  return 0;
+}
+
+static inline const char *
+__attribute__ ((unused))
+_dl_hwcap_string (int idx)
+{
+  return GLRO(dl_mips_cap_flags)[idx];
+};
 
-/* We don't have any hardware capabilities.  */
-#define _DL_HWCAP_COUNT	0
+static inline int
+__attribute__ ((unused))
+_dl_string_hwcap (const char *str)
+{
+  int i;
 
-#define _dl_string_hwcap(str) (-1)
+  for (i = 0; i < _DL_HWCAP_COUNT; i++)
+    {
+      if (strcmp (str, GLRO(dl_mips_cap_flags)[i]) == 0)
+	return i;
+    }
+  return -1;
+};
 
 #endif /* dl-procinfo.h */