]>
Commit | Line | Data |
---|---|---|
2b778ceb | 1 | /* Copyright (C) 1992-2021 Free Software Foundation, Inc. |
dc37f3e5 | 2 | This file is part of the GNU C Library. |
56759be2 | 3 | |
dc37f3e5 | 4 | The GNU C Library is free software; you can redistribute it and/or |
3214b89b AJ |
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. | |
56759be2 | 8 | |
dc37f3e5 UD |
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 | |
3214b89b | 12 | Lesser General Public License for more details. |
56759be2 | 13 | |
3214b89b | 14 | You should have received a copy of the GNU Lesser General Public |
ab84e3ff | 15 | License along with the GNU C Library. If not, see |
5a82c748 | 16 | <https://www.gnu.org/licenses/>. */ |
56759be2 RM |
17 | |
18 | /* I/O access is restricted to ISA port space (ports 0..65535). | |
dc37f3e5 UD |
19 | Modern devices hopefully are sane enough not to put any performance |
20 | critical registers in i/o space. | |
56759be2 | 21 | |
194b9b3b RH |
22 | On the first call to ioperm, the entire (E)ISA port space is mapped |
23 | into the virtual address space at address io.base. mprotect calls | |
24 | are then used to enable/disable access to ports. Per page, there | |
25 | are PAGE_SIZE>>IO_SHIFT I/O ports (e.g., 256 ports on a Low Cost Alpha | |
26 | based system using 8KB pages). | |
56759be2 | 27 | |
dc37f3e5 UD |
28 | Keep in mind that this code should be able to run in a 32bit address |
29 | space. It is therefore unreasonable to expect mmap'ing the entire | |
30 | sparse address space would work (e.g., the Low Cost Alpha chip has an | |
31 | I/O address space that's 512MB large!). */ | |
56759be2 | 32 | |
91d46f8a RH |
33 | /* Make sure the ldbu/stb asms below are not expaneded to macros. */ |
34 | #ifndef __alpha_bwx__ | |
35 | asm(".arch ev56"); | |
36 | #endif | |
37 | ||
56759be2 RM |
38 | #include <errno.h> |
39 | #include <fcntl.h> | |
40 | #include <stdio.h> | |
d44e5674 | 41 | #include <ctype.h> |
15999cfb | 42 | #include <stdlib.h> |
56759be2 | 43 | #include <string.h> |
15999cfb | 44 | #include <unistd.h> |
56759be2 RM |
45 | |
46 | #include <sys/types.h> | |
47 | #include <sys/mman.h> | |
194b9b3b | 48 | #include <sys/io.h> |
56759be2 | 49 | |
194b9b3b RH |
50 | #include <sysdep.h> |
51 | #include <sys/syscall.h> | |
56759be2 | 52 | |
15999cfb RM |
53 | #define PATH_ALPHA_SYSTYPE "/etc/alpha_systype" |
54 | #define PATH_CPUINFO "/proc/cpuinfo" | |
56759be2 RM |
55 | |
56 | #define MAX_PORT 0x10000 | |
194b9b3b | 57 | #define vip volatile int * |
56759be2 | 58 | #define vuip volatile unsigned int * |
194b9b3b RH |
59 | #define vusp volatile unsigned short * |
60 | #define vucp volatile unsigned char * | |
56759be2 | 61 | |
194b9b3b RH |
62 | #define JENSEN_IO_BASE (0x300000000UL) |
63 | #define JENSEN_SPARSE_MEM (0x200000000UL) | |
15999cfb | 64 | |
2521516d UD |
65 | /* With respect to the I/O architecture, APECS and LCA are identical, |
66 | so the following defines apply to LCA as well. */ | |
194b9b3b RH |
67 | #define APECS_IO_BASE (0x1c0000000UL) |
68 | #define APECS_SPARSE_MEM (0x200000000UL) | |
69 | #define APECS_DENSE_MEM (0x300000000UL) | |
15999cfb | 70 | |
194b9b3b RH |
71 | /* The same holds for CIA and PYXIS, except for PYXIS we prefer BWX. */ |
72 | #define CIA_IO_BASE (0x8580000000UL) | |
73 | #define CIA_SPARSE_MEM (0x8000000000UL) | |
74 | #define CIA_DENSE_MEM (0x8600000000UL) | |
15999cfb | 75 | |
194b9b3b RH |
76 | #define PYXIS_IO_BASE (0x8900000000UL) |
77 | #define PYXIS_DENSE_MEM (0x8800000000UL) | |
56759be2 | 78 | |
194b9b3b RH |
79 | /* SABLE is EV4, GAMMA is EV5 */ |
80 | #define T2_IO_BASE (0x3a0000000UL) | |
81 | #define T2_SPARSE_MEM (0x200000000UL) | |
82 | #define T2_DENSE_MEM (0x3c0000000UL) | |
a8d236a8 | 83 | |
194b9b3b RH |
84 | #define GAMMA_IO_BASE (0x83a0000000UL) |
85 | #define GAMMA_SPARSE_MEM (0x8200000000UL) | |
86 | #define GAMMA_DENSE_MEM (0x83c0000000UL) | |
a8d236a8 | 87 | |
a8d236a8 | 88 | /* NOTE: these are hardwired to PCI bus 0 addresses!!! */ |
194b9b3b RH |
89 | #define MCPCIA_IO_BASE (0xf980000000UL) |
90 | #define MCPCIA_SPARSE_MEM (0xf800000000UL) | |
91 | #define MCPCIA_DENSE_MEM (0xf900000000UL) | |
92 | ||
93 | /* Tsunami and Irongate use the same offsets, at least for hose 0. */ | |
94 | #define TSUNAMI_IO_BASE (0x801fc000000UL) | |
95 | #define TSUNAMI_DENSE_MEM (0x80000000000UL) | |
a8d236a8 | 96 | |
194b9b3b RH |
97 | /* Polaris has SPARSE space, but we prefer to use only DENSE |
98 | because of some idiosyncracies in actually using SPARSE. */ | |
99 | #define POLARIS_IO_BASE (0xf9fc000000UL) | |
100 | #define POLARIS_DENSE_MEM (0xf900000000UL) | |
05246799 | 101 | |
dc37f3e5 | 102 | typedef enum { |
194b9b3b | 103 | IOSYS_UNKNOWN, IOSYS_JENSEN, IOSYS_APECS, IOSYS_CIA, IOSYS_PYXIS, IOSYS_T2, |
05246799 UD |
104 | IOSYS_TSUNAMI, IOSYS_MCPCIA, IOSYS_GAMMA, IOSYS_POLARIS, |
105 | IOSYS_CPUDEP, IOSYS_PCIDEP | |
56759be2 RM |
106 | } iosys_t; |
107 | ||
05246799 UD |
108 | typedef enum { |
109 | IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE | |
110 | } ioswizzle_t; | |
111 | ||
a8d236a8 | 112 | static struct io_system { |
a8d236a8 UD |
113 | unsigned long int bus_memory_base; |
114 | unsigned long int sparse_bus_mem_base; | |
115 | unsigned long int bus_io_base; | |
116 | } io_system[] = { /* NOTE! must match iosys_t enumeration */ | |
194b9b3b RH |
117 | /* UNKNOWN */ {0, 0, 0}, |
118 | /* JENSEN */ {0, JENSEN_SPARSE_MEM, JENSEN_IO_BASE}, | |
119 | /* APECS */ {APECS_DENSE_MEM, APECS_SPARSE_MEM, APECS_IO_BASE}, | |
120 | /* CIA */ {CIA_DENSE_MEM, CIA_SPARSE_MEM, CIA_IO_BASE}, | |
121 | /* PYXIS */ {PYXIS_DENSE_MEM, 0, PYXIS_IO_BASE}, | |
122 | /* T2 */ {T2_DENSE_MEM, T2_SPARSE_MEM, T2_IO_BASE}, | |
123 | /* TSUNAMI */ {TSUNAMI_DENSE_MEM, 0, TSUNAMI_IO_BASE}, | |
124 | /* MCPCIA */ {MCPCIA_DENSE_MEM, MCPCIA_SPARSE_MEM, MCPCIA_IO_BASE}, | |
125 | /* GAMMA */ {GAMMA_DENSE_MEM, GAMMA_SPARSE_MEM, GAMMA_IO_BASE}, | |
126 | /* POLARIS */ {POLARIS_DENSE_MEM, 0, POLARIS_IO_BASE}, | |
127 | /* CPUDEP */ {0, 0, 0}, /* for platforms dependent on CPU type */ | |
128 | /* PCIDEP */ {0, 0, 0}, /* for platforms dependent on core logic */ | |
a8d236a8 UD |
129 | }; |
130 | ||
131 | static struct platform { | |
132 | const char *name; | |
133 | iosys_t io_sys; | |
134 | } platform[] = { | |
135 | {"Alcor", IOSYS_CIA}, | |
136 | {"Avanti", IOSYS_APECS}, | |
a8d236a8 | 137 | {"Cabriolet", IOSYS_APECS}, |
05246799 | 138 | {"EB164", IOSYS_PCIDEP}, |
a8d236a8 UD |
139 | {"EB64+", IOSYS_APECS}, |
140 | {"EB66", IOSYS_APECS}, | |
141 | {"EB66P", IOSYS_APECS}, | |
142 | {"Jensen", IOSYS_JENSEN}, | |
194b9b3b | 143 | {"Miata", IOSYS_PYXIS}, |
a8d236a8 | 144 | {"Mikasa", IOSYS_CPUDEP}, |
052065ad | 145 | {"Nautilus", IOSYS_TSUNAMI}, |
194b9b3b RH |
146 | {"Noname", IOSYS_APECS}, |
147 | {"Noritake", IOSYS_CPUDEP}, | |
a8d236a8 | 148 | {"Rawhide", IOSYS_MCPCIA}, |
194b9b3b RH |
149 | {"Ruffian", IOSYS_PYXIS}, |
150 | {"Sable", IOSYS_CPUDEP}, | |
a8d236a8 | 151 | {"Takara", IOSYS_CIA}, |
194b9b3b RH |
152 | {"Tsunami", IOSYS_TSUNAMI}, |
153 | {"XL", IOSYS_APECS}, | |
a8d236a8 UD |
154 | }; |
155 | ||
56759be2 | 156 | struct ioswtch { |
dc37f3e5 UD |
157 | void (*sethae)(unsigned long int addr); |
158 | void (*outb)(unsigned char b, unsigned long int port); | |
159 | void (*outw)(unsigned short b, unsigned long int port); | |
160 | void (*outl)(unsigned int b, unsigned long int port); | |
161 | unsigned int (*inb)(unsigned long int port); | |
162 | unsigned int (*inw)(unsigned long int port); | |
163 | unsigned int (*inl)(unsigned long int port); | |
56759be2 RM |
164 | }; |
165 | ||
56759be2 | 166 | static struct { |
194b9b3b | 167 | unsigned long int hae_cache; |
dc37f3e5 | 168 | unsigned long int base; |
56759be2 | 169 | struct ioswtch * swp; |
dc37f3e5 UD |
170 | unsigned long int bus_memory_base; |
171 | unsigned long int sparse_bus_memory_base; | |
172 | unsigned long int io_base; | |
05246799 | 173 | ioswizzle_t swiz; |
56759be2 RM |
174 | } io; |
175 | ||
194b9b3b RH |
176 | static inline void |
177 | stb_mb(unsigned char val, unsigned long addr) | |
178 | { | |
179 | __asm__("stb %1,%0; mb" : "=m"(*(vucp)addr) : "r"(val)); | |
180 | } | |
181 | ||
182 | static inline void | |
183 | stw_mb(unsigned short val, unsigned long addr) | |
184 | { | |
185 | __asm__("stw %1,%0; mb" : "=m"(*(vusp)addr) : "r"(val)); | |
186 | } | |
187 | ||
188 | static inline void | |
189 | stl_mb(unsigned int val, unsigned long addr) | |
190 | { | |
191 | __asm__("stl %1,%0; mb" : "=m"(*(vip)addr) : "r"(val)); | |
192 | } | |
193 | ||
194 | /* No need to examine error -- sethae never fails. */ | |
195 | static inline void | |
196 | __sethae(unsigned long value) | |
197 | { | |
975ace4e | 198 | INLINE_SYSCALL_CALL (sethae, value); |
194b9b3b RH |
199 | } |
200 | ||
201 | extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which, | |
202 | unsigned long int __bus, | |
203 | unsigned long int __dfn); | |
15999cfb | 204 | |
dc37f3e5 | 205 | static inline unsigned long int |
05246799 | 206 | port_to_cpu_addr (unsigned long int port, ioswizzle_t ioswiz, int size) |
56759be2 | 207 | { |
05246799 | 208 | if (ioswiz == IOSWIZZLE_SPARSE) |
194b9b3b | 209 | return io.base + (port << 5) + ((size - 1) << 3); |
05246799 | 210 | else if (ioswiz == IOSWIZZLE_DENSE) |
a8d236a8 | 211 | return port + io.base; |
15999cfb | 212 | else |
194b9b3b | 213 | return io.base + (port << 7) + ((size - 1) << 5); |
56759be2 RM |
214 | } |
215 | ||
ee78ea88 | 216 | static inline __attribute__((always_inline)) void |
05246799 | 217 | inline_sethae (unsigned long int addr, ioswizzle_t ioswiz) |
56759be2 | 218 | { |
05246799 | 219 | if (ioswiz == IOSWIZZLE_SPARSE) |
15999cfb | 220 | { |
dc37f3e5 | 221 | unsigned long int msb; |
15999cfb RM |
222 | |
223 | /* no need to set hae if msb is 0: */ | |
224 | msb = addr & 0xf8000000; | |
194b9b3b | 225 | if (msb && msb != io.hae_cache) |
15999cfb | 226 | { |
194b9b3b | 227 | io.hae_cache = msb; |
15999cfb | 228 | __sethae (msb); |
15999cfb | 229 | } |
56759be2 | 230 | } |
194b9b3b | 231 | else if (ioswiz == IOSWIZZLE_JENSEN) |
05246799 | 232 | { |
194b9b3b | 233 | /* HAE on the Jensen is bits 31:25 shifted right. */ |
05246799 | 234 | addr >>= 25; |
194b9b3b | 235 | if (addr != io.hae_cache) |
05246799 | 236 | { |
194b9b3b | 237 | io.hae_cache = addr; |
05246799 | 238 | __sethae (addr); |
05246799 UD |
239 | } |
240 | } | |
56759be2 RM |
241 | } |
242 | ||
56759be2 | 243 | static inline void |
05246799 | 244 | inline_outb (unsigned char b, unsigned long int port, ioswizzle_t ioswiz) |
56759be2 RM |
245 | { |
246 | unsigned int w; | |
05246799 | 247 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1); |
56759be2 | 248 | |
f3afb0ff | 249 | asm ("insbl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b)); |
194b9b3b | 250 | stl_mb(w, addr); |
56759be2 RM |
251 | } |
252 | ||
253 | ||
254 | static inline void | |
05246799 | 255 | inline_outw (unsigned short int b, unsigned long int port, ioswizzle_t ioswiz) |
56759be2 | 256 | { |
194b9b3b | 257 | unsigned long w; |
05246799 | 258 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2); |
56759be2 | 259 | |
f3afb0ff | 260 | asm ("inswl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b)); |
194b9b3b | 261 | stl_mb(w, addr); |
56759be2 RM |
262 | } |
263 | ||
264 | ||
265 | static inline void | |
05246799 | 266 | inline_outl (unsigned int b, unsigned long int port, ioswizzle_t ioswiz) |
56759be2 | 267 | { |
05246799 | 268 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4); |
56759be2 | 269 | |
194b9b3b | 270 | stl_mb(b, addr); |
56759be2 RM |
271 | } |
272 | ||
273 | ||
274 | static inline unsigned int | |
05246799 | 275 | inline_inb (unsigned long int port, ioswizzle_t ioswiz) |
56759be2 | 276 | { |
194b9b3b RH |
277 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1); |
278 | int result; | |
56759be2 | 279 | |
194b9b3b | 280 | result = *(vip) addr; |
56759be2 RM |
281 | result >>= (port & 3) * 8; |
282 | return 0xffUL & result; | |
283 | } | |
284 | ||
285 | ||
286 | static inline unsigned int | |
05246799 | 287 | inline_inw (unsigned long int port, ioswizzle_t ioswiz) |
56759be2 | 288 | { |
194b9b3b RH |
289 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2); |
290 | int result; | |
56759be2 | 291 | |
194b9b3b | 292 | result = *(vip) addr; |
56759be2 RM |
293 | result >>= (port & 3) * 8; |
294 | return 0xffffUL & result; | |
295 | } | |
296 | ||
297 | ||
298 | static inline unsigned int | |
05246799 | 299 | inline_inl (unsigned long int port, ioswizzle_t ioswiz) |
56759be2 | 300 | { |
05246799 | 301 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4); |
56759be2 | 302 | |
56759be2 RM |
303 | return *(vuip) addr; |
304 | } | |
305 | ||
a8d236a8 UD |
306 | /* |
307 | * Now define the inline functions for CPUs supporting byte/word insns, | |
308 | * and whose core logic supports I/O space accesses utilizing them. | |
309 | * | |
310 | * These routines could be used by MIATA, for example, because it has | |
05246799 UD |
311 | * and EV56 plus PYXIS, but it currently uses SPARSE anyway. This is |
312 | * also true of RX164 which used POLARIS, but we will choose to use | |
313 | * these routines in that case instead of SPARSE. | |
a8d236a8 UD |
314 | * |
315 | * These routines are necessary for TSUNAMI/TYPHOON based platforms, | |
316 | * which will have (at least) EV6. | |
317 | */ | |
318 | ||
05246799 UD |
319 | static inline unsigned long int |
320 | dense_port_to_cpu_addr (unsigned long int port) | |
321 | { | |
322 | return port + io.base; | |
323 | } | |
324 | ||
a8d236a8 | 325 | static inline void |
05246799 | 326 | inline_bwx_outb (unsigned char b, unsigned long int port) |
a8d236a8 | 327 | { |
05246799 | 328 | unsigned long int addr = dense_port_to_cpu_addr (port); |
194b9b3b | 329 | stb_mb (b, addr); |
a8d236a8 UD |
330 | } |
331 | ||
a8d236a8 | 332 | static inline void |
05246799 | 333 | inline_bwx_outw (unsigned short int b, unsigned long int port) |
a8d236a8 | 334 | { |
05246799 | 335 | unsigned long int addr = dense_port_to_cpu_addr (port); |
194b9b3b | 336 | stw_mb (b, addr); |
a8d236a8 UD |
337 | } |
338 | ||
a8d236a8 | 339 | static inline void |
05246799 | 340 | inline_bwx_outl (unsigned int b, unsigned long int port) |
a8d236a8 | 341 | { |
05246799 | 342 | unsigned long int addr = dense_port_to_cpu_addr (port); |
194b9b3b | 343 | stl_mb (b, addr); |
a8d236a8 UD |
344 | } |
345 | ||
a8d236a8 | 346 | static inline unsigned int |
05246799 | 347 | inline_bwx_inb (unsigned long int port) |
a8d236a8 | 348 | { |
194b9b3b RH |
349 | unsigned long int addr = dense_port_to_cpu_addr (port); |
350 | unsigned char r; | |
a8d236a8 | 351 | |
194b9b3b RH |
352 | __asm__ ("ldbu %0,%1" : "=r"(r) : "m"(*(vucp)addr)); |
353 | return r; | |
a8d236a8 UD |
354 | } |
355 | ||
a8d236a8 | 356 | static inline unsigned int |
05246799 | 357 | inline_bwx_inw (unsigned long int port) |
a8d236a8 | 358 | { |
194b9b3b RH |
359 | unsigned long int addr = dense_port_to_cpu_addr (port); |
360 | unsigned short r; | |
a8d236a8 | 361 | |
194b9b3b RH |
362 | __asm__ ("ldwu %0,%1" : "=r"(r) : "m"(*(vusp)addr)); |
363 | return r; | |
a8d236a8 UD |
364 | } |
365 | ||
a8d236a8 | 366 | static inline unsigned int |
05246799 | 367 | inline_bwx_inl (unsigned long int port) |
a8d236a8 | 368 | { |
05246799 | 369 | unsigned long int addr = dense_port_to_cpu_addr (port); |
a8d236a8 UD |
370 | |
371 | return *(vuip) addr; | |
372 | } | |
373 | ||
05246799 | 374 | /* macros to define routines with appropriate names and functions */ |
a8d236a8 | 375 | |
05246799 UD |
376 | /* these do either SPARSE or JENSEN swizzle */ |
377 | ||
378 | #define DCL_SETHAE(name, ioswiz) \ | |
379 | static void \ | |
380 | name##_sethae (unsigned long int addr) \ | |
381 | { \ | |
382 | inline_sethae (addr, IOSWIZZLE_##ioswiz); \ | |
56759be2 RM |
383 | } |
384 | ||
05246799 | 385 | #define DCL_OUT(name, func, type, ioswiz) \ |
56759be2 | 386 | static void \ |
dc37f3e5 | 387 | name##_##func (unsigned type b, unsigned long int addr) \ |
56759be2 | 388 | { \ |
05246799 | 389 | inline_##func (b, addr, IOSWIZZLE_##ioswiz); \ |
56759be2 RM |
390 | } |
391 | ||
05246799 | 392 | #define DCL_IN(name, func, ioswiz) \ |
56759be2 | 393 | static unsigned int \ |
dc37f3e5 | 394 | name##_##func (unsigned long int addr) \ |
56759be2 | 395 | { \ |
05246799 | 396 | return inline_##func (addr, IOSWIZZLE_##ioswiz); \ |
56759be2 RM |
397 | } |
398 | ||
05246799 | 399 | /* these do DENSE, so no swizzle is needed */ |
a8d236a8 | 400 | |
05246799 | 401 | #define DCL_OUT_BWX(name, func, type) \ |
a8d236a8 UD |
402 | static void \ |
403 | name##_##func (unsigned type b, unsigned long int addr) \ | |
404 | { \ | |
05246799 | 405 | inline_bwx_##func (b, addr); \ |
a8d236a8 UD |
406 | } |
407 | ||
05246799 | 408 | #define DCL_IN_BWX(name, func) \ |
a8d236a8 UD |
409 | static unsigned int \ |
410 | name##_##func (unsigned long int addr) \ | |
411 | { \ | |
05246799 | 412 | return inline_bwx_##func (addr); \ |
a8d236a8 UD |
413 | } |
414 | ||
05246799 | 415 | /* now declare/define the necessary routines */ |
56759be2 RM |
416 | |
417 | DCL_SETHAE(jensen, JENSEN) | |
418 | DCL_OUT(jensen, outb, char, JENSEN) | |
dc37f3e5 | 419 | DCL_OUT(jensen, outw, short int, JENSEN) |
56759be2 RM |
420 | DCL_OUT(jensen, outl, int, JENSEN) |
421 | DCL_IN(jensen, inb, JENSEN) | |
422 | DCL_IN(jensen, inw, JENSEN) | |
423 | DCL_IN(jensen, inl, JENSEN) | |
424 | ||
05246799 UD |
425 | DCL_SETHAE(sparse, SPARSE) |
426 | DCL_OUT(sparse, outb, char, SPARSE) | |
427 | DCL_OUT(sparse, outw, short int, SPARSE) | |
428 | DCL_OUT(sparse, outl, int, SPARSE) | |
429 | DCL_IN(sparse, inb, SPARSE) | |
430 | DCL_IN(sparse, inw, SPARSE) | |
431 | DCL_IN(sparse, inl, SPARSE) | |
432 | ||
194b9b3b | 433 | DCL_SETHAE(dense, DENSE) |
05246799 UD |
434 | DCL_OUT_BWX(dense, outb, char) |
435 | DCL_OUT_BWX(dense, outw, short int) | |
436 | DCL_OUT_BWX(dense, outl, int) | |
437 | DCL_IN_BWX(dense, inb) | |
438 | DCL_IN_BWX(dense, inw) | |
439 | DCL_IN_BWX(dense, inl) | |
440 | ||
441 | /* define the "swizzle" switch */ | |
a8d236a8 | 442 | static struct ioswtch ioswtch[] = { |
56759be2 RM |
443 | { |
444 | jensen_sethae, | |
445 | jensen_outb, jensen_outw, jensen_outl, | |
446 | jensen_inb, jensen_inw, jensen_inl | |
447 | }, | |
448 | { | |
05246799 UD |
449 | sparse_sethae, |
450 | sparse_outb, sparse_outw, sparse_outl, | |
451 | sparse_inb, sparse_inw, sparse_inl | |
a8d236a8 UD |
452 | }, |
453 | { | |
194b9b3b | 454 | dense_sethae, |
05246799 UD |
455 | dense_outb, dense_outw, dense_outl, |
456 | dense_inb, dense_inw, dense_inl | |
56759be2 RM |
457 | } |
458 | }; | |
459 | ||
c628e038 UD |
460 | #undef DEBUG_IOPERM |
461 | ||
194b9b3b RH |
462 | /* Routine to process the /proc/cpuinfo information into the fields |
463 | that are required for correctly determining the platform parameters. */ | |
05246799 | 464 | |
194b9b3b RH |
465 | struct cpuinfo_data |
466 | { | |
467 | char systype[256]; /* system type field */ | |
468 | char sysvari[256]; /* system variation field */ | |
469 | char cpumodel[256]; /* cpu model field */ | |
470 | }; | |
05246799 | 471 | |
194b9b3b RH |
472 | static inline int |
473 | process_cpuinfo(struct cpuinfo_data *data) | |
05246799 | 474 | { |
194b9b3b | 475 | int got_type, got_vari, got_model; |
05246799 UD |
476 | char dummy[256]; |
477 | FILE * fp; | |
194b9b3b RH |
478 | int n; |
479 | ||
480 | data->systype[0] = 0; | |
481 | data->sysvari[0] = 0; | |
482 | data->cpumodel[0] = 0; | |
483 | ||
484 | /* If there's an /etc/alpha_systype link, we're intending to override | |
485 | whatever's in /proc/cpuinfo. */ | |
486 | n = __readlink (PATH_ALPHA_SYSTYPE, data->systype, 256 - 1); | |
487 | if (n > 0) | |
488 | { | |
489 | data->systype[n] = '\0'; | |
490 | return 1; | |
491 | } | |
56759be2 | 492 | |
99449c15 | 493 | fp = fopen (PATH_CPUINFO, "rce"); |
05246799 UD |
494 | if (!fp) |
495 | return 0; | |
496 | ||
497 | got_type = got_vari = got_model = 0; | |
05246799 UD |
498 | |
499 | while (1) | |
500 | { | |
a797e173 | 501 | if (fgets_unlocked (dummy, 256, fp) == NULL) |
194b9b3b | 502 | break; |
aa0e4663 JM |
503 | if (!got_type |
504 | && sscanf (dummy, "system type : %256[^\n]\n", data->systype) == 1) | |
05246799 | 505 | got_type = 1; |
aa0e4663 JM |
506 | if (!got_vari |
507 | && (sscanf (dummy, "system variation : %256[^\n]\n", data->sysvari) | |
508 | == 1)) | |
05246799 | 509 | got_vari = 1; |
aa0e4663 JM |
510 | if (!got_model |
511 | && sscanf (dummy, "cpu model : %256[^\n]\n", data->cpumodel) == 1) | |
05246799 UD |
512 | got_model = 1; |
513 | } | |
514 | ||
515 | fclose (fp); | |
516 | ||
c628e038 | 517 | #ifdef DEBUG_IOPERM |
194b9b3b RH |
518 | fprintf(stderr, "system type: `%s'\n", data->systype); |
519 | fprintf(stderr, "system vari: `%s'\n", data->sysvari); | |
520 | fprintf(stderr, "cpu model: `%s'\n", data->cpumodel); | |
05246799 UD |
521 | #endif |
522 | ||
194b9b3b | 523 | return got_type + got_vari + got_model; |
05246799 | 524 | } |
194b9b3b RH |
525 | |
526 | ||
15999cfb | 527 | /* |
194b9b3b | 528 | * Initialize I/O system. |
15999cfb | 529 | */ |
56759be2 RM |
530 | static int |
531 | init_iosys (void) | |
532 | { | |
194b9b3b RH |
533 | long addr; |
534 | int i, olderrno = errno; | |
535 | struct cpuinfo_data data; | |
56759be2 | 536 | |
194b9b3b RH |
537 | /* First try the pciconfig_iobase syscall added to 2.2.15 and 2.3.99. */ |
538 | ||
539 | addr = __pciconfig_iobase (IOBASE_DENSE_MEM, 0, 0); | |
540 | if (addr != -1) | |
15999cfb | 541 | { |
194b9b3b RH |
542 | ioswizzle_t io_swiz; |
543 | ||
544 | if (addr == 0) | |
545 | { | |
546 | /* Only Jensen doesn't have dense mem space. */ | |
547 | io.sparse_bus_memory_base | |
548 | = io_system[IOSYS_JENSEN].sparse_bus_mem_base; | |
549 | io.io_base = io_system[IOSYS_JENSEN].bus_io_base; | |
550 | io_swiz = IOSWIZZLE_JENSEN; | |
551 | } | |
552 | else | |
dc37f3e5 | 553 | { |
194b9b3b RH |
554 | io.bus_memory_base = addr; |
555 | ||
556 | addr = __pciconfig_iobase (IOBASE_DENSE_IO, 0, 0); | |
557 | if (addr != 0) | |
558 | { | |
559 | /* The X server uses _bus_base_sparse == 0 to know that | |
560 | BWX access are supported to dense mem space. This is | |
561 | true of every system that supports dense io space, so | |
562 | never fill in io.sparse_bus_memory_base in this case. */ | |
563 | io_swiz = IOSWIZZLE_DENSE; | |
564 | io.io_base = addr; | |
565 | } | |
566 | else | |
dc37f3e5 | 567 | { |
194b9b3b RH |
568 | io.sparse_bus_memory_base |
569 | = __pciconfig_iobase (IOBASE_SPARSE_MEM, 0, 0); | |
570 | io.io_base = __pciconfig_iobase (IOBASE_SPARSE_IO, 0, 0); | |
571 | io_swiz = IOSWIZZLE_SPARSE; | |
dc37f3e5 | 572 | } |
dc37f3e5 | 573 | } |
194b9b3b RH |
574 | |
575 | io.swiz = io_swiz; | |
576 | io.swp = &ioswtch[io_swiz]; | |
577 | ||
578 | return 0; | |
15999cfb | 579 | } |
15999cfb | 580 | |
194b9b3b RH |
581 | /* Second, collect the contents of /etc/alpha_systype or /proc/cpuinfo. */ |
582 | ||
583 | if (process_cpuinfo(&data) == 0) | |
584 | { | |
585 | /* This can happen if the format of /proc/cpuinfo changes. */ | |
586 | fprintf (stderr, | |
587 | "ioperm.init_iosys: Unable to determine system type.\n" | |
588 | "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n"); | |
589 | __set_errno (ENODEV); | |
590 | return -1; | |
15999cfb | 591 | } |
56759be2 | 592 | |
194b9b3b | 593 | /* Translate systype name into i/o system. */ |
15999cfb RM |
594 | for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i) |
595 | { | |
194b9b3b | 596 | if (strcmp (platform[i].name, data.systype) == 0) |
15999cfb | 597 | { |
194b9b3b RH |
598 | iosys_t io_sys = platform[i].io_sys; |
599 | ||
600 | /* Some platforms can have either EV4 or EV5 CPUs. */ | |
601 | if (io_sys == IOSYS_CPUDEP) | |
a8d236a8 | 602 | { |
194b9b3b | 603 | /* SABLE or MIKASA or NORITAKE so far. */ |
a8d236a8 UD |
604 | if (strcmp (platform[i].name, "Sable") == 0) |
605 | { | |
194b9b3b RH |
606 | if (strncmp (data.cpumodel, "EV4", 3) == 0) |
607 | io_sys = IOSYS_T2; | |
608 | else if (strncmp (data.cpumodel, "EV5", 3) == 0) | |
609 | io_sys = IOSYS_GAMMA; | |
a8d236a8 UD |
610 | } |
611 | else | |
194b9b3b RH |
612 | { |
613 | /* This covers MIKASA/NORITAKE. */ | |
614 | if (strncmp (data.cpumodel, "EV4", 3) == 0) | |
615 | io_sys = IOSYS_APECS; | |
616 | else if (strncmp (data.cpumodel, "EV5", 3) == 0) | |
617 | io_sys = IOSYS_CIA; | |
a8d236a8 | 618 | } |
194b9b3b | 619 | if (io_sys == IOSYS_CPUDEP) |
a8d236a8 UD |
620 | { |
621 | /* This can happen if the format of /proc/cpuinfo changes.*/ | |
194b9b3b | 622 | fprintf (stderr, "ioperm.init_iosys: Unable to determine" |
a8d236a8 UD |
623 | " CPU model.\n"); |
624 | __set_errno (ENODEV); | |
625 | return -1; | |
626 | } | |
627 | } | |
194b9b3b RH |
628 | /* Some platforms can have different core logic chipsets */ |
629 | if (io_sys == IOSYS_PCIDEP) | |
05246799 | 630 | { |
194b9b3b RH |
631 | /* EB164 so far */ |
632 | if (strcmp (data.systype, "EB164") == 0) | |
05246799 | 633 | { |
194b9b3b RH |
634 | if (strncmp (data.sysvari, "RX164", 5) == 0) |
635 | io_sys = IOSYS_POLARIS; | |
636 | else if (strncmp (data.sysvari, "LX164", 5) == 0 | |
637 | || strncmp (data.sysvari, "SX164", 5) == 0) | |
638 | io_sys = IOSYS_PYXIS; | |
05246799 | 639 | else |
194b9b3b | 640 | io_sys = IOSYS_CIA; |
05246799 | 641 | } |
194b9b3b | 642 | if (io_sys == IOSYS_PCIDEP) |
05246799 UD |
643 | { |
644 | /* This can happen if the format of /proc/cpuinfo changes.*/ | |
194b9b3b | 645 | fprintf (stderr, "ioperm.init_iosys: Unable to determine" |
05246799 UD |
646 | " core logic chipset.\n"); |
647 | __set_errno (ENODEV); | |
648 | return -1; | |
649 | } | |
650 | } | |
194b9b3b RH |
651 | io.bus_memory_base = io_system[io_sys].bus_memory_base; |
652 | io.sparse_bus_memory_base = io_system[io_sys].sparse_bus_mem_base; | |
653 | io.io_base = io_system[io_sys].bus_io_base; | |
a8d236a8 | 654 | |
194b9b3b | 655 | if (io_sys == IOSYS_JENSEN) |
05246799 | 656 | io.swiz = IOSWIZZLE_JENSEN; |
194b9b3b RH |
657 | else if (io_sys == IOSYS_TSUNAMI |
658 | || io_sys == IOSYS_POLARIS | |
659 | || io_sys == IOSYS_PYXIS) | |
05246799 | 660 | io.swiz = IOSWIZZLE_DENSE; |
56759be2 | 661 | else |
05246799 UD |
662 | io.swiz = IOSWIZZLE_SPARSE; |
663 | io.swp = &ioswtch[io.swiz]; | |
194b9b3b RH |
664 | |
665 | __set_errno (olderrno); | |
56759be2 RM |
666 | return 0; |
667 | } | |
56759be2 | 668 | } |
15999cfb | 669 | |
194b9b3b RH |
670 | __set_errno (ENODEV); |
671 | fprintf(stderr, "ioperm.init_iosys: Platform not recognized.\n" | |
672 | "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n"); | |
56759be2 RM |
673 | return -1; |
674 | } | |
675 | ||
676 | ||
677 | int | |
dc37f3e5 | 678 | _ioperm (unsigned long int from, unsigned long int num, int turn_on) |
56759be2 | 679 | { |
194b9b3b RH |
680 | unsigned long int addr, len, pagesize = __getpagesize(); |
681 | int prot; | |
56759be2 | 682 | |
194b9b3b RH |
683 | if (!io.swp && init_iosys() < 0) |
684 | { | |
c628e038 | 685 | #ifdef DEBUG_IOPERM |
194b9b3b | 686 | fprintf(stderr, "ioperm: init_iosys() failed (%m)\n"); |
05246799 | 687 | #endif |
194b9b3b RH |
688 | return -1; |
689 | } | |
56759be2 | 690 | |
194b9b3b | 691 | /* This test isn't as silly as it may look like; consider overflows! */ |
15999cfb RM |
692 | if (from >= MAX_PORT || from + num > MAX_PORT) |
693 | { | |
1120c0ed | 694 | __set_errno (EINVAL); |
c628e038 | 695 | #ifdef DEBUG_IOPERM |
05246799 UD |
696 | fprintf(stderr, "ioperm: from/num out of range\n"); |
697 | #endif | |
15999cfb RM |
698 | return -1; |
699 | } | |
56759be2 | 700 | |
c628e038 | 701 | #ifdef DEBUG_IOPERM |
194b9b3b | 702 | fprintf(stderr, "ioperm: turn_on %d io.base %ld\n", turn_on, io.base); |
05246799 UD |
703 | #endif |
704 | ||
15999cfb RM |
705 | if (turn_on) |
706 | { | |
707 | if (!io.base) | |
708 | { | |
15999cfb RM |
709 | int fd; |
710 | ||
194b9b3b | 711 | io.hae_cache = 0; |
05246799 | 712 | if (io.swiz != IOSWIZZLE_DENSE) |
194b9b3b RH |
713 | { |
714 | /* Synchronize with hw. */ | |
715 | __sethae (0); | |
716 | } | |
15999cfb | 717 | |
194b9b3b RH |
718 | fd = __open ("/dev/mem", O_RDWR); |
719 | if (fd < 0) | |
720 | { | |
c628e038 | 721 | #ifdef DEBUG_IOPERM |
194b9b3b | 722 | fprintf(stderr, "ioperm: /dev/mem open failed (%m)\n"); |
05246799 | 723 | #endif |
194b9b3b RH |
724 | return -1; |
725 | } | |
15999cfb | 726 | |
05246799 UD |
727 | addr = port_to_cpu_addr (0, io.swiz, 1); |
728 | len = port_to_cpu_addr (MAX_PORT, io.swiz, 1) - addr; | |
15999cfb | 729 | io.base = |
dc37f3e5 | 730 | (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED, |
a8d236a8 | 731 | fd, io.io_base); |
194b9b3b | 732 | __close (fd); |
c628e038 | 733 | #ifdef DEBUG_IOPERM |
05246799 UD |
734 | fprintf(stderr, "ioperm: mmap of len 0x%lx returned 0x%lx\n", |
735 | len, io.base); | |
736 | #endif | |
15999cfb RM |
737 | if ((long) io.base == -1) |
738 | return -1; | |
739 | } | |
740 | prot = PROT_READ | PROT_WRITE; | |
56759be2 | 741 | } |
15999cfb RM |
742 | else |
743 | { | |
744 | if (!io.base) | |
745 | return 0; /* never was turned on... */ | |
56759be2 | 746 | |
15999cfb RM |
747 | /* turnoff access to relevant pages: */ |
748 | prot = PROT_NONE; | |
749 | } | |
05246799 | 750 | addr = port_to_cpu_addr (from, io.swiz, 1); |
194b9b3b | 751 | addr &= ~(pagesize - 1); |
05246799 | 752 | len = port_to_cpu_addr (from + num, io.swiz, 1) - addr; |
194b9b3b | 753 | return __mprotect ((void *) addr, len, prot); |
56759be2 RM |
754 | } |
755 | ||
756 | ||
757 | int | |
194b9b3b RH |
758 | _iopl (int level) |
759 | { | |
760 | switch (level) | |
761 | { | |
762 | case 0: | |
763 | return 0; | |
764 | ||
765 | case 1: case 2: case 3: | |
766 | return _ioperm (0, MAX_PORT, 1); | |
767 | ||
768 | default: | |
769 | __set_errno (EINVAL); | |
770 | return -1; | |
771 | } | |
56759be2 RM |
772 | } |
773 | ||
774 | ||
775 | void | |
dc37f3e5 | 776 | _sethae (unsigned long int addr) |
56759be2 RM |
777 | { |
778 | if (!io.swp && init_iosys () < 0) | |
779 | return; | |
780 | ||
781 | io.swp->sethae (addr); | |
782 | } | |
783 | ||
784 | ||
785 | void | |
dc37f3e5 | 786 | _outb (unsigned char b, unsigned long int port) |
56759be2 RM |
787 | { |
788 | if (port >= MAX_PORT) | |
789 | return; | |
790 | ||
791 | io.swp->outb (b, port); | |
792 | } | |
793 | ||
794 | ||
795 | void | |
dc37f3e5 | 796 | _outw (unsigned short b, unsigned long int port) |
56759be2 RM |
797 | { |
798 | if (port >= MAX_PORT) | |
799 | return; | |
800 | ||
801 | io.swp->outw (b, port); | |
802 | } | |
803 | ||
804 | ||
805 | void | |
dc37f3e5 | 806 | _outl (unsigned int b, unsigned long int port) |
56759be2 RM |
807 | { |
808 | if (port >= MAX_PORT) | |
809 | return; | |
810 | ||
811 | io.swp->outl (b, port); | |
812 | } | |
813 | ||
814 | ||
815 | unsigned int | |
dc37f3e5 | 816 | _inb (unsigned long int port) |
56759be2 RM |
817 | { |
818 | return io.swp->inb (port); | |
819 | } | |
820 | ||
821 | ||
822 | unsigned int | |
dc37f3e5 | 823 | _inw (unsigned long int port) |
56759be2 RM |
824 | { |
825 | return io.swp->inw (port); | |
826 | } | |
827 | ||
828 | ||
829 | unsigned int | |
dc37f3e5 | 830 | _inl (unsigned long int port) |
56759be2 RM |
831 | { |
832 | return io.swp->inl (port); | |
833 | } | |
834 | ||
835 | ||
dc37f3e5 | 836 | unsigned long int |
15999cfb RM |
837 | _bus_base(void) |
838 | { | |
839 | if (!io.swp && init_iosys () < 0) | |
840 | return -1; | |
11309adf | 841 | return io.bus_memory_base; |
15999cfb RM |
842 | } |
843 | ||
dc37f3e5 | 844 | unsigned long int |
dca26bcb UD |
845 | _bus_base_sparse(void) |
846 | { | |
847 | if (!io.swp && init_iosys () < 0) | |
848 | return -1; | |
11309adf UD |
849 | return io.sparse_bus_memory_base; |
850 | } | |
851 | ||
852 | int | |
853 | _hae_shift(void) | |
854 | { | |
855 | if (!io.swp && init_iosys () < 0) | |
856 | return -1; | |
194b9b3b RH |
857 | if (io.swiz == IOSWIZZLE_JENSEN) |
858 | return 7; | |
859 | if (io.swiz == IOSWIZZLE_SPARSE) | |
860 | return 5; | |
861 | return 0; | |
dca26bcb UD |
862 | } |
863 | ||
56759be2 RM |
864 | weak_alias (_sethae, sethae); |
865 | weak_alias (_ioperm, ioperm); | |
866 | weak_alias (_iopl, iopl); | |
867 | weak_alias (_inb, inb); | |
868 | weak_alias (_inw, inw); | |
869 | weak_alias (_inl, inl); | |
870 | weak_alias (_outb, outb); | |
871 | weak_alias (_outw, outw); | |
872 | weak_alias (_outl, outl); | |
15999cfb | 873 | weak_alias (_bus_base, bus_base); |
dca26bcb | 874 | weak_alias (_bus_base_sparse, bus_base_sparse); |
11309adf | 875 | weak_alias (_hae_shift, hae_shift); |