Move tilegx, tilepro, and linux-generic from ports to libc.
[jlayton/glibc.git] / sysdeps / unix / sysv / linux / tile / tilegx / sched_getcpu.c
1 /* Copyright (C) 2012-2014 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library.  If not, see
16    <http://www.gnu.org/licenses/>.  */
17
18 #include <errno.h>
19 #include <stddef.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <sched.h>
23 #include <sysdep.h>
24 #include <arch/spr_def.h>
25
26
27 /* The count of cores horizontally (X dimension) on the chip.  */
28 static int chip_width;
29
30 /* Read the chip "width" from the /sys filesystem.  */
31 static int
32 initialize_chip_width (void)
33 {
34   int w = 0;
35   int fd;
36
37   fd = __open ("/sys/devices/system/cpu/chip_width", O_RDONLY);
38   if (fd >= 0)
39     {
40       char buf[64];
41       ssize_t n;
42       int i;
43
44       n = __read (fd, buf, sizeof (buf));
45       __close (fd);
46
47       for (i = 0; i < n; ++i)
48         {
49           if (buf[i] < '0' || buf[i] > '9')
50             break;
51           w = (w * 10) + (buf[i] - '0');
52         }
53     }
54
55   /* Store a negative value so we don't try again.  */
56   if (w == 0)
57     w = -1;
58
59   /* Using an atomic idempotent write here makes this thread-safe.  */
60   chip_width = w;
61   return w;
62 }
63
64 int
65 sched_getcpu (void)
66 {
67   unsigned int coord;
68   int w = chip_width;
69
70   if (__builtin_expect (w <= 0, 0))
71     {
72       if (w == 0)
73         w = initialize_chip_width ();
74       if (w < 0)
75         {
76           unsigned int cpu;
77           int r = INLINE_SYSCALL (getcpu, 3, &cpu, NULL, NULL);
78           return r == -1 ? r : cpu;
79         }
80     }
81
82   /* Assign 64-bit value to a 32-bit variable to ensure 32-bit multiply.  */
83   coord = __insn_mfspr (SPR_TILE_COORD);
84
85   /* Extract Y coord from bits 7..10 and X coord from bits 18..21.  */
86   return ((coord >> 7) & 0xf) * w + ((coord >> 18) & 0xf);
87 }