]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/alpha/ioperm.c
Remove "Contributed by" lines
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / alpha / ioperm.c
CommitLineData
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__
35asm(".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 102typedef 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
108typedef enum {
109 IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE
110} ioswizzle_t;
111
a8d236a8 112static 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
131static 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 156struct 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 166static 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
176static inline void
177stb_mb(unsigned char val, unsigned long addr)
178{
179 __asm__("stb %1,%0; mb" : "=m"(*(vucp)addr) : "r"(val));
180}
181
182static inline void
183stw_mb(unsigned short val, unsigned long addr)
184{
185 __asm__("stw %1,%0; mb" : "=m"(*(vusp)addr) : "r"(val));
186}
187
188static inline void
189stl_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. */
195static inline void
196__sethae(unsigned long value)
197{
975ace4e 198 INLINE_SYSCALL_CALL (sethae, value);
194b9b3b
RH
199}
200
201extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which,
202 unsigned long int __bus,
203 unsigned long int __dfn);
15999cfb 204
dc37f3e5 205static inline unsigned long int
05246799 206port_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 216static inline __attribute__((always_inline)) void
05246799 217inline_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 243static inline void
05246799 244inline_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
254static inline void
05246799 255inline_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
265static inline void
05246799 266inline_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
274static inline unsigned int
05246799 275inline_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
286static inline unsigned int
05246799 287inline_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
298static inline unsigned int
05246799 299inline_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
319static inline unsigned long int
320dense_port_to_cpu_addr (unsigned long int port)
321{
322 return port + io.base;
323}
324
a8d236a8 325static inline void
05246799 326inline_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 332static inline void
05246799 333inline_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 339static inline void
05246799 340inline_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 346static inline unsigned int
05246799 347inline_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 356static inline unsigned int
05246799 357inline_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 366static inline unsigned int
05246799 367inline_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) \
379static void \
380name##_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 386static void \
dc37f3e5 387name##_##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 393static unsigned int \
dc37f3e5 394name##_##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
402static void \
403name##_##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
409static unsigned int \
410name##_##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
417DCL_SETHAE(jensen, JENSEN)
418DCL_OUT(jensen, outb, char, JENSEN)
dc37f3e5 419DCL_OUT(jensen, outw, short int, JENSEN)
56759be2
RM
420DCL_OUT(jensen, outl, int, JENSEN)
421DCL_IN(jensen, inb, JENSEN)
422DCL_IN(jensen, inw, JENSEN)
423DCL_IN(jensen, inl, JENSEN)
424
05246799
UD
425DCL_SETHAE(sparse, SPARSE)
426DCL_OUT(sparse, outb, char, SPARSE)
427DCL_OUT(sparse, outw, short int, SPARSE)
428DCL_OUT(sparse, outl, int, SPARSE)
429DCL_IN(sparse, inb, SPARSE)
430DCL_IN(sparse, inw, SPARSE)
431DCL_IN(sparse, inl, SPARSE)
432
194b9b3b 433DCL_SETHAE(dense, DENSE)
05246799
UD
434DCL_OUT_BWX(dense, outb, char)
435DCL_OUT_BWX(dense, outw, short int)
436DCL_OUT_BWX(dense, outl, int)
437DCL_IN_BWX(dense, inb)
438DCL_IN_BWX(dense, inw)
439DCL_IN_BWX(dense, inl)
440
441/* define the "swizzle" switch */
a8d236a8 442static 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
465struct 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
472static inline int
473process_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
530static int
531init_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
677int
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
757int
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
775void
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
785void
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
795void
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
805void
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
815unsigned int
dc37f3e5 816_inb (unsigned long int port)
56759be2
RM
817{
818 return io.swp->inb (port);
819}
820
821
822unsigned int
dc37f3e5 823_inw (unsigned long int port)
56759be2
RM
824{
825 return io.swp->inw (port);
826}
827
828
829unsigned int
dc37f3e5 830_inl (unsigned long int port)
56759be2
RM
831{
832 return io.swp->inl (port);
833}
834
835
dc37f3e5 836unsigned 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 844unsigned 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
852int
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
864weak_alias (_sethae, sethae);
865weak_alias (_ioperm, ioperm);
866weak_alias (_iopl, iopl);
867weak_alias (_inb, inb);
868weak_alias (_inw, inw);
869weak_alias (_inl, inl);
870weak_alias (_outb, outb);
871weak_alias (_outw, outw);
872weak_alias (_outl, outl);
15999cfb 873weak_alias (_bus_base, bus_base);
dca26bcb 874weak_alias (_bus_base_sparse, bus_base_sparse);
11309adf 875weak_alias (_hae_shift, hae_shift);