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