1 | /* Copyright (C) 1992-2022 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 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* I/O access is restricted to ISA port space (ports 0..65535). |
19 | Modern devices hopefully are sane enough not to put any performance |
20 | critical registers in i/o space. |
21 | |
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). |
27 | |
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!). */ |
32 | |
33 | /* Make sure the ldbu/stb asms below are not expaneded to macros. */ |
34 | #ifndef __alpha_bwx__ |
35 | asm(".arch ev56" ); |
36 | #endif |
37 | |
38 | #include <errno.h> |
39 | #include <fcntl.h> |
40 | #include <stdio.h> |
41 | #include <ctype.h> |
42 | #include <stdlib.h> |
43 | #include <string.h> |
44 | #include <unistd.h> |
45 | |
46 | #include <sys/types.h> |
47 | #include <sys/mman.h> |
48 | #include <sys/io.h> |
49 | |
50 | #include <sysdep.h> |
51 | #include <sys/syscall.h> |
52 | |
53 | #define PATH_ALPHA_SYSTYPE "/etc/alpha_systype" |
54 | #define PATH_CPUINFO "/proc/cpuinfo" |
55 | |
56 | #define MAX_PORT 0x10000 |
57 | #define vip volatile int * |
58 | #define vuip volatile unsigned int * |
59 | #define vusp volatile unsigned short * |
60 | #define vucp volatile unsigned char * |
61 | |
62 | #define JENSEN_IO_BASE (0x300000000UL) |
63 | #define JENSEN_SPARSE_MEM (0x200000000UL) |
64 | |
65 | /* With respect to the I/O architecture, APECS and LCA are identical, |
66 | so the following defines apply to LCA as well. */ |
67 | #define APECS_IO_BASE (0x1c0000000UL) |
68 | #define APECS_SPARSE_MEM (0x200000000UL) |
69 | #define APECS_DENSE_MEM (0x300000000UL) |
70 | |
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) |
75 | |
76 | #define PYXIS_IO_BASE (0x8900000000UL) |
77 | #define PYXIS_DENSE_MEM (0x8800000000UL) |
78 | |
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) |
83 | |
84 | #define GAMMA_IO_BASE (0x83a0000000UL) |
85 | #define GAMMA_SPARSE_MEM (0x8200000000UL) |
86 | #define GAMMA_DENSE_MEM (0x83c0000000UL) |
87 | |
88 | /* NOTE: these are hardwired to PCI bus 0 addresses!!! */ |
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) |
96 | |
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) |
101 | |
102 | typedef enum { |
103 | IOSYS_UNKNOWN, IOSYS_JENSEN, IOSYS_APECS, IOSYS_CIA, IOSYS_PYXIS, IOSYS_T2, |
104 | IOSYS_TSUNAMI, IOSYS_MCPCIA, IOSYS_GAMMA, IOSYS_POLARIS, |
105 | IOSYS_CPUDEP, IOSYS_PCIDEP |
106 | } iosys_t; |
107 | |
108 | typedef enum { |
109 | IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE |
110 | } ioswizzle_t; |
111 | |
112 | static struct io_system { |
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 */ |
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 */ |
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}, |
137 | {"Cabriolet" , IOSYS_APECS}, |
138 | {"EB164" , IOSYS_PCIDEP}, |
139 | {"EB64+" , IOSYS_APECS}, |
140 | {"EB66" , IOSYS_APECS}, |
141 | {"EB66P" , IOSYS_APECS}, |
142 | {"Jensen" , IOSYS_JENSEN}, |
143 | {"Miata" , IOSYS_PYXIS}, |
144 | {"Mikasa" , IOSYS_CPUDEP}, |
145 | {"Nautilus" , IOSYS_TSUNAMI}, |
146 | {"Noname" , IOSYS_APECS}, |
147 | {"Noritake" , IOSYS_CPUDEP}, |
148 | {"Rawhide" , IOSYS_MCPCIA}, |
149 | {"Ruffian" , IOSYS_PYXIS}, |
150 | {"Sable" , IOSYS_CPUDEP}, |
151 | {"Takara" , IOSYS_CIA}, |
152 | {"Tsunami" , IOSYS_TSUNAMI}, |
153 | {"XL" , IOSYS_APECS}, |
154 | }; |
155 | |
156 | struct ioswtch { |
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); |
164 | }; |
165 | |
166 | static struct { |
167 | unsigned long int hae_cache; |
168 | unsigned long int base; |
169 | struct ioswtch * swp; |
170 | unsigned long int bus_memory_base; |
171 | unsigned long int sparse_bus_memory_base; |
172 | unsigned long int io_base; |
173 | ioswizzle_t swiz; |
174 | } io; |
175 | |
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 | { |
198 | INLINE_SYSCALL_CALL (sethae, value); |
199 | } |
200 | |
201 | extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which, |
202 | unsigned long int __bus, |
203 | unsigned long int __dfn); |
204 | |
205 | static inline unsigned long int |
206 | port_to_cpu_addr (unsigned long int port, ioswizzle_t ioswiz, int size) |
207 | { |
208 | if (ioswiz == IOSWIZZLE_SPARSE) |
209 | return io.base + (port << 5) + ((size - 1) << 3); |
210 | else if (ioswiz == IOSWIZZLE_DENSE) |
211 | return port + io.base; |
212 | else |
213 | return io.base + (port << 7) + ((size - 1) << 5); |
214 | } |
215 | |
216 | static inline __attribute__((always_inline)) void |
217 | inline_sethae (unsigned long int addr, ioswizzle_t ioswiz) |
218 | { |
219 | if (ioswiz == IOSWIZZLE_SPARSE) |
220 | { |
221 | unsigned long int msb; |
222 | |
223 | /* no need to set hae if msb is 0: */ |
224 | msb = addr & 0xf8000000; |
225 | if (msb && msb != io.hae_cache) |
226 | { |
227 | io.hae_cache = msb; |
228 | __sethae (value: msb); |
229 | } |
230 | } |
231 | else if (ioswiz == IOSWIZZLE_JENSEN) |
232 | { |
233 | /* HAE on the Jensen is bits 31:25 shifted right. */ |
234 | addr >>= 25; |
235 | if (addr != io.hae_cache) |
236 | { |
237 | io.hae_cache = addr; |
238 | __sethae (value: addr); |
239 | } |
240 | } |
241 | } |
242 | |
243 | static inline void |
244 | inline_outb (unsigned char b, unsigned long int port, ioswizzle_t ioswiz) |
245 | { |
246 | unsigned int w; |
247 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, size: 1); |
248 | |
249 | asm ("insbl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b)); |
250 | stl_mb(val: w, addr); |
251 | } |
252 | |
253 | |
254 | static inline void |
255 | inline_outw (unsigned short int b, unsigned long int port, ioswizzle_t ioswiz) |
256 | { |
257 | unsigned long w; |
258 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, size: 2); |
259 | |
260 | asm ("inswl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b)); |
261 | stl_mb(val: w, addr); |
262 | } |
263 | |
264 | |
265 | static inline void |
266 | inline_outl (unsigned int b, unsigned long int port, ioswizzle_t ioswiz) |
267 | { |
268 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, size: 4); |
269 | |
270 | stl_mb(val: b, addr); |
271 | } |
272 | |
273 | |
274 | static inline unsigned int |
275 | inline_inb (unsigned long int port, ioswizzle_t ioswiz) |
276 | { |
277 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, size: 1); |
278 | int result; |
279 | |
280 | result = *(vip) addr; |
281 | result >>= (port & 3) * 8; |
282 | return 0xffUL & result; |
283 | } |
284 | |
285 | |
286 | static inline unsigned int |
287 | inline_inw (unsigned long int port, ioswizzle_t ioswiz) |
288 | { |
289 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, size: 2); |
290 | int result; |
291 | |
292 | result = *(vip) addr; |
293 | result >>= (port & 3) * 8; |
294 | return 0xffffUL & result; |
295 | } |
296 | |
297 | |
298 | static inline unsigned int |
299 | inline_inl (unsigned long int port, ioswizzle_t ioswiz) |
300 | { |
301 | unsigned long int addr = port_to_cpu_addr (port, ioswiz, size: 4); |
302 | |
303 | return *(vuip) addr; |
304 | } |
305 | |
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 |
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. |
314 | * |
315 | * These routines are necessary for TSUNAMI/TYPHOON based platforms, |
316 | * which will have (at least) EV6. |
317 | */ |
318 | |
319 | static inline unsigned long int |
320 | dense_port_to_cpu_addr (unsigned long int port) |
321 | { |
322 | return port + io.base; |
323 | } |
324 | |
325 | static inline void |
326 | inline_bwx_outb (unsigned char b, unsigned long int port) |
327 | { |
328 | unsigned long int addr = dense_port_to_cpu_addr (port); |
329 | stb_mb (val: b, addr); |
330 | } |
331 | |
332 | static inline void |
333 | inline_bwx_outw (unsigned short int b, unsigned long int port) |
334 | { |
335 | unsigned long int addr = dense_port_to_cpu_addr (port); |
336 | stw_mb (val: b, addr); |
337 | } |
338 | |
339 | static inline void |
340 | inline_bwx_outl (unsigned int b, unsigned long int port) |
341 | { |
342 | unsigned long int addr = dense_port_to_cpu_addr (port); |
343 | stl_mb (val: b, addr); |
344 | } |
345 | |
346 | static inline unsigned int |
347 | inline_bwx_inb (unsigned long int port) |
348 | { |
349 | unsigned long int addr = dense_port_to_cpu_addr (port); |
350 | unsigned char r; |
351 | |
352 | __asm__ ("ldbu %0,%1" : "=r" (r) : "m" (*(vucp)addr)); |
353 | return r; |
354 | } |
355 | |
356 | static inline unsigned int |
357 | inline_bwx_inw (unsigned long int port) |
358 | { |
359 | unsigned long int addr = dense_port_to_cpu_addr (port); |
360 | unsigned short r; |
361 | |
362 | __asm__ ("ldwu %0,%1" : "=r" (r) : "m" (*(vusp)addr)); |
363 | return r; |
364 | } |
365 | |
366 | static inline unsigned int |
367 | inline_bwx_inl (unsigned long int port) |
368 | { |
369 | unsigned long int addr = dense_port_to_cpu_addr (port); |
370 | |
371 | return *(vuip) addr; |
372 | } |
373 | |
374 | /* macros to define routines with appropriate names and functions */ |
375 | |
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); \ |
383 | } |
384 | |
385 | #define DCL_OUT(name, func, type, ioswiz) \ |
386 | static void \ |
387 | name##_##func (unsigned type b, unsigned long int addr) \ |
388 | { \ |
389 | inline_##func (b, addr, IOSWIZZLE_##ioswiz); \ |
390 | } |
391 | |
392 | #define DCL_IN(name, func, ioswiz) \ |
393 | static unsigned int \ |
394 | name##_##func (unsigned long int addr) \ |
395 | { \ |
396 | return inline_##func (addr, IOSWIZZLE_##ioswiz); \ |
397 | } |
398 | |
399 | /* these do DENSE, so no swizzle is needed */ |
400 | |
401 | #define DCL_OUT_BWX(name, func, type) \ |
402 | static void \ |
403 | name##_##func (unsigned type b, unsigned long int addr) \ |
404 | { \ |
405 | inline_bwx_##func (b, addr); \ |
406 | } |
407 | |
408 | #define DCL_IN_BWX(name, func) \ |
409 | static unsigned int \ |
410 | name##_##func (unsigned long int addr) \ |
411 | { \ |
412 | return inline_bwx_##func (addr); \ |
413 | } |
414 | |
415 | /* now declare/define the necessary routines */ |
416 | |
417 | DCL_SETHAE(jensen, JENSEN) |
418 | DCL_OUT(jensen, outb, char, JENSEN) |
419 | DCL_OUT(jensen, outw, short int, JENSEN) |
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 | |
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 | |
433 | DCL_SETHAE(dense, DENSE) |
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 */ |
442 | static struct ioswtch ioswtch[] = { |
443 | { |
444 | jensen_sethae, |
445 | jensen_outb, jensen_outw, jensen_outl, |
446 | jensen_inb, jensen_inw, jensen_inl |
447 | }, |
448 | { |
449 | sparse_sethae, |
450 | sparse_outb, sparse_outw, sparse_outl, |
451 | sparse_inb, sparse_inw, sparse_inl |
452 | }, |
453 | { |
454 | dense_sethae, |
455 | dense_outb, dense_outw, dense_outl, |
456 | dense_inb, dense_inw, dense_inl |
457 | } |
458 | }; |
459 | |
460 | #undef DEBUG_IOPERM |
461 | |
462 | /* Routine to process the /proc/cpuinfo information into the fields |
463 | that are required for correctly determining the platform parameters. */ |
464 | |
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 | }; |
471 | |
472 | static inline int |
473 | process_cpuinfo(struct cpuinfo_data *data) |
474 | { |
475 | int got_type, got_vari, got_model; |
476 | char dummy[256]; |
477 | FILE * fp; |
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, buf: data->systype, len: 256 - 1); |
487 | if (n > 0) |
488 | { |
489 | data->systype[n] = '\0'; |
490 | return 1; |
491 | } |
492 | |
493 | fp = fopen (PATH_CPUINFO, "rce" ); |
494 | if (!fp) |
495 | return 0; |
496 | |
497 | got_type = got_vari = got_model = 0; |
498 | |
499 | while (1) |
500 | { |
501 | if (fgets_unlocked (dummy, 256, fp) == NULL) |
502 | break; |
503 | if (!got_type |
504 | && sscanf (dummy, "system type : %256[^\n]\n" , data->systype) == 1) |
505 | got_type = 1; |
506 | if (!got_vari |
507 | && (sscanf (dummy, "system variation : %256[^\n]\n" , data->sysvari) |
508 | == 1)) |
509 | got_vari = 1; |
510 | if (!got_model |
511 | && sscanf (dummy, "cpu model : %256[^\n]\n" , data->cpumodel) == 1) |
512 | got_model = 1; |
513 | } |
514 | |
515 | fclose (fp); |
516 | |
517 | #ifdef DEBUG_IOPERM |
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); |
521 | #endif |
522 | |
523 | return got_type + got_vari + got_model; |
524 | } |
525 | |
526 | |
527 | /* |
528 | * Initialize I/O system. |
529 | */ |
530 | static int |
531 | init_iosys (void) |
532 | { |
533 | long addr; |
534 | int i, olderrno = errno; |
535 | struct cpuinfo_data data; |
536 | |
537 | /* First try the pciconfig_iobase syscall added to 2.2.15 and 2.3.99. */ |
538 | |
539 | addr = __pciconfig_iobase (which: IOBASE_DENSE_MEM, bus: 0, dfn: 0); |
540 | if (addr != -1) |
541 | { |
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 |
553 | { |
554 | io.bus_memory_base = addr; |
555 | |
556 | addr = __pciconfig_iobase (which: IOBASE_DENSE_IO, bus: 0, dfn: 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 |
567 | { |
568 | io.sparse_bus_memory_base |
569 | = __pciconfig_iobase (which: IOBASE_SPARSE_MEM, bus: 0, dfn: 0); |
570 | io.io_base = __pciconfig_iobase (which: IOBASE_SPARSE_IO, bus: 0, dfn: 0); |
571 | io_swiz = IOSWIZZLE_SPARSE; |
572 | } |
573 | } |
574 | |
575 | io.swiz = io_swiz; |
576 | io.swp = &ioswtch[io_swiz]; |
577 | |
578 | return 0; |
579 | } |
580 | |
581 | /* Second, collect the contents of /etc/alpha_systype or /proc/cpuinfo. */ |
582 | |
583 | if (process_cpuinfo(data: &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; |
591 | } |
592 | |
593 | /* Translate systype name into i/o system. */ |
594 | for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i) |
595 | { |
596 | if (strcmp (platform[i].name, data.systype) == 0) |
597 | { |
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) |
602 | { |
603 | /* SABLE or MIKASA or NORITAKE so far. */ |
604 | if (strcmp (platform[i].name, "Sable" ) == 0) |
605 | { |
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; |
610 | } |
611 | else |
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; |
618 | } |
619 | if (io_sys == IOSYS_CPUDEP) |
620 | { |
621 | /* This can happen if the format of /proc/cpuinfo changes.*/ |
622 | fprintf (stderr, "ioperm.init_iosys: Unable to determine" |
623 | " CPU model.\n" ); |
624 | __set_errno (ENODEV); |
625 | return -1; |
626 | } |
627 | } |
628 | /* Some platforms can have different core logic chipsets */ |
629 | if (io_sys == IOSYS_PCIDEP) |
630 | { |
631 | /* EB164 so far */ |
632 | if (strcmp (data.systype, "EB164" ) == 0) |
633 | { |
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; |
639 | else |
640 | io_sys = IOSYS_CIA; |
641 | } |
642 | if (io_sys == IOSYS_PCIDEP) |
643 | { |
644 | /* This can happen if the format of /proc/cpuinfo changes.*/ |
645 | fprintf (stderr, "ioperm.init_iosys: Unable to determine" |
646 | " core logic chipset.\n" ); |
647 | __set_errno (ENODEV); |
648 | return -1; |
649 | } |
650 | } |
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; |
654 | |
655 | if (io_sys == IOSYS_JENSEN) |
656 | io.swiz = IOSWIZZLE_JENSEN; |
657 | else if (io_sys == IOSYS_TSUNAMI |
658 | || io_sys == IOSYS_POLARIS |
659 | || io_sys == IOSYS_PYXIS) |
660 | io.swiz = IOSWIZZLE_DENSE; |
661 | else |
662 | io.swiz = IOSWIZZLE_SPARSE; |
663 | io.swp = &ioswtch[io.swiz]; |
664 | |
665 | __set_errno (olderrno); |
666 | return 0; |
667 | } |
668 | } |
669 | |
670 | __set_errno (ENODEV); |
671 | fprintf(stderr, "ioperm.init_iosys: Platform not recognized.\n" |
672 | "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n" ); |
673 | return -1; |
674 | } |
675 | |
676 | |
677 | int |
678 | _ioperm (unsigned long int from, unsigned long int num, int turn_on) |
679 | { |
680 | unsigned long int addr, len, pagesize = __getpagesize(); |
681 | int prot; |
682 | |
683 | if (!io.swp && init_iosys() < 0) |
684 | { |
685 | #ifdef DEBUG_IOPERM |
686 | fprintf(stderr, "ioperm: init_iosys() failed (%m)\n" ); |
687 | #endif |
688 | return -1; |
689 | } |
690 | |
691 | /* This test isn't as silly as it may look like; consider overflows! */ |
692 | if (from >= MAX_PORT || from + num > MAX_PORT) |
693 | { |
694 | __set_errno (EINVAL); |
695 | #ifdef DEBUG_IOPERM |
696 | fprintf(stderr, "ioperm: from/num out of range\n" ); |
697 | #endif |
698 | return -1; |
699 | } |
700 | |
701 | #ifdef DEBUG_IOPERM |
702 | fprintf(stderr, "ioperm: turn_on %d io.base %ld\n" , turn_on, io.base); |
703 | #endif |
704 | |
705 | if (turn_on) |
706 | { |
707 | if (!io.base) |
708 | { |
709 | int fd; |
710 | |
711 | io.hae_cache = 0; |
712 | if (io.swiz != IOSWIZZLE_DENSE) |
713 | { |
714 | /* Synchronize with hw. */ |
715 | __sethae (value: 0); |
716 | } |
717 | |
718 | fd = __open ("/dev/mem" , O_RDWR); |
719 | if (fd < 0) |
720 | { |
721 | #ifdef DEBUG_IOPERM |
722 | fprintf(stderr, "ioperm: /dev/mem open failed (%m)\n" ); |
723 | #endif |
724 | return -1; |
725 | } |
726 | |
727 | addr = port_to_cpu_addr (port: 0, ioswiz: io.swiz, size: 1); |
728 | len = port_to_cpu_addr (MAX_PORT, ioswiz: io.swiz, size: 1) - addr; |
729 | io.base = |
730 | (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED, |
731 | fd, io.io_base); |
732 | __close (fd); |
733 | #ifdef DEBUG_IOPERM |
734 | fprintf(stderr, "ioperm: mmap of len 0x%lx returned 0x%lx\n" , |
735 | len, io.base); |
736 | #endif |
737 | if ((long) io.base == -1) |
738 | return -1; |
739 | } |
740 | prot = PROT_READ | PROT_WRITE; |
741 | } |
742 | else |
743 | { |
744 | if (!io.base) |
745 | return 0; /* never was turned on... */ |
746 | |
747 | /* turnoff access to relevant pages: */ |
748 | prot = PROT_NONE; |
749 | } |
750 | addr = port_to_cpu_addr (port: from, ioswiz: io.swiz, size: 1); |
751 | addr &= ~(pagesize - 1); |
752 | len = port_to_cpu_addr (port: from + num, ioswiz: io.swiz, size: 1) - addr; |
753 | return __mprotect ((void *) addr, len, prot); |
754 | } |
755 | |
756 | |
757 | int |
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 (from: 0, MAX_PORT, turn_on: 1); |
767 | |
768 | default: |
769 | __set_errno (EINVAL); |
770 | return -1; |
771 | } |
772 | } |
773 | |
774 | |
775 | void |
776 | _sethae (unsigned long int addr) |
777 | { |
778 | if (!io.swp && init_iosys () < 0) |
779 | return; |
780 | |
781 | io.swp->sethae (addr); |
782 | } |
783 | |
784 | |
785 | void |
786 | _outb (unsigned char b, unsigned long int port) |
787 | { |
788 | if (port >= MAX_PORT) |
789 | return; |
790 | |
791 | io.swp->outb (b, port); |
792 | } |
793 | |
794 | |
795 | void |
796 | _outw (unsigned short b, unsigned long int port) |
797 | { |
798 | if (port >= MAX_PORT) |
799 | return; |
800 | |
801 | io.swp->outw (b, port); |
802 | } |
803 | |
804 | |
805 | void |
806 | _outl (unsigned int b, unsigned long int port) |
807 | { |
808 | if (port >= MAX_PORT) |
809 | return; |
810 | |
811 | io.swp->outl (b, port); |
812 | } |
813 | |
814 | |
815 | unsigned int |
816 | _inb (unsigned long int port) |
817 | { |
818 | return io.swp->inb (port); |
819 | } |
820 | |
821 | |
822 | unsigned int |
823 | _inw (unsigned long int port) |
824 | { |
825 | return io.swp->inw (port); |
826 | } |
827 | |
828 | |
829 | unsigned int |
830 | _inl (unsigned long int port) |
831 | { |
832 | return io.swp->inl (port); |
833 | } |
834 | |
835 | |
836 | unsigned long int |
837 | _bus_base(void) |
838 | { |
839 | if (!io.swp && init_iosys () < 0) |
840 | return -1; |
841 | return io.bus_memory_base; |
842 | } |
843 | |
844 | unsigned long int |
845 | _bus_base_sparse(void) |
846 | { |
847 | if (!io.swp && init_iosys () < 0) |
848 | return -1; |
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; |
857 | if (io.swiz == IOSWIZZLE_JENSEN) |
858 | return 7; |
859 | if (io.swiz == IOSWIZZLE_SPARSE) |
860 | return 5; |
861 | return 0; |
862 | } |
863 | |
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); |
873 | weak_alias (_bus_base, bus_base); |
874 | weak_alias (_bus_base_sparse, bus_base_sparse); |
875 | weak_alias (_hae_shift, hae_shift); |
876 | |