1 /* Copyright (C) 1992, 1996-1999, 2000 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by David Mosberger.
5 The GNU C Library is free software; you can redistribute it and/or
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.
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
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 /* I/O access is restricted to ISA port space (ports 0..65535).
21 Modern devices hopefully are sane enough not to put any performance
22 critical registers in i/o space.
24 On the first call to ioperm, the entire (E)ISA port space is mapped
25 into the virtual address space at address io.base. mprotect calls
26 are then used to enable/disable access to ports. Per page, there
27 are PAGE_SIZE>>IO_SHIFT I/O ports (e.g., 256 ports on a Low Cost Alpha
28 based system using 8KB pages).
30 Keep in mind that this code should be able to run in a 32bit address
31 space. It is therefore unreasonable to expect mmap'ing the entire
32 sparse address space would work (e.g., the Low Cost Alpha chip has an
33 I/O address space that's 512MB large!). */
43 #include <sys/types.h>
48 #include <sys/syscall.h>
50 #define PATH_ALPHA_SYSTYPE "/etc/alpha_systype"
51 #define PATH_CPUINFO "/proc/cpuinfo"
53 #define MAX_PORT 0x10000
54 #define vip volatile int *
55 #define vuip volatile unsigned int *
56 #define vusp volatile unsigned short *
57 #define vucp volatile unsigned char *
59 #define JENSEN_IO_BASE (0x300000000UL)
60 #define JENSEN_SPARSE_MEM (0x200000000UL)
62 /* With respect to the I/O architecture, APECS and LCA are identical,
63 so the following defines apply to LCA as well. */
64 #define APECS_IO_BASE (0x1c0000000UL)
65 #define APECS_SPARSE_MEM (0x200000000UL)
66 #define APECS_DENSE_MEM (0x300000000UL)
68 /* The same holds for CIA and PYXIS, except for PYXIS we prefer BWX. */
69 #define CIA_IO_BASE (0x8580000000UL)
70 #define CIA_SPARSE_MEM (0x8000000000UL)
71 #define CIA_DENSE_MEM (0x8600000000UL)
73 #define PYXIS_IO_BASE (0x8900000000UL)
74 #define PYXIS_DENSE_MEM (0x8800000000UL)
76 /* SABLE is EV4, GAMMA is EV5 */
77 #define T2_IO_BASE (0x3a0000000UL)
78 #define T2_SPARSE_MEM (0x200000000UL)
79 #define T2_DENSE_MEM (0x3c0000000UL)
81 #define GAMMA_IO_BASE (0x83a0000000UL)
82 #define GAMMA_SPARSE_MEM (0x8200000000UL)
83 #define GAMMA_DENSE_MEM (0x83c0000000UL)
85 /* NOTE: these are hardwired to PCI bus 0 addresses!!! */
86 #define MCPCIA_IO_BASE (0xf980000000UL)
87 #define MCPCIA_SPARSE_MEM (0xf800000000UL)
88 #define MCPCIA_DENSE_MEM (0xf900000000UL)
90 /* Tsunami and Irongate use the same offsets, at least for hose 0. */
91 #define TSUNAMI_IO_BASE (0x801fc000000UL)
92 #define TSUNAMI_DENSE_MEM (0x80000000000UL)
94 /* Polaris has SPARSE space, but we prefer to use only DENSE
95 because of some idiosyncracies in actually using SPARSE. */
96 #define POLARIS_IO_BASE (0xf9fc000000UL)
97 #define POLARIS_DENSE_MEM (0xf900000000UL)
100 IOSYS_UNKNOWN, IOSYS_JENSEN, IOSYS_APECS, IOSYS_CIA, IOSYS_PYXIS, IOSYS_T2,
101 IOSYS_TSUNAMI, IOSYS_MCPCIA, IOSYS_GAMMA, IOSYS_POLARIS,
102 IOSYS_CPUDEP, IOSYS_PCIDEP
106 IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE
109 static struct io_system {
110 unsigned long int bus_memory_base;
111 unsigned long int sparse_bus_mem_base;
112 unsigned long int bus_io_base;
113 } io_system[] = { /* NOTE! must match iosys_t enumeration */
114 /* UNKNOWN */ {0, 0, 0},
115 /* JENSEN */ {0, JENSEN_SPARSE_MEM, JENSEN_IO_BASE},
116 /* APECS */ {APECS_DENSE_MEM, APECS_SPARSE_MEM, APECS_IO_BASE},
117 /* CIA */ {CIA_DENSE_MEM, CIA_SPARSE_MEM, CIA_IO_BASE},
118 /* PYXIS */ {PYXIS_DENSE_MEM, 0, PYXIS_IO_BASE},
119 /* T2 */ {T2_DENSE_MEM, T2_SPARSE_MEM, T2_IO_BASE},
120 /* TSUNAMI */ {TSUNAMI_DENSE_MEM, 0, TSUNAMI_IO_BASE},
121 /* MCPCIA */ {MCPCIA_DENSE_MEM, MCPCIA_SPARSE_MEM, MCPCIA_IO_BASE},
122 /* GAMMA */ {GAMMA_DENSE_MEM, GAMMA_SPARSE_MEM, GAMMA_IO_BASE},
123 /* POLARIS */ {POLARIS_DENSE_MEM, 0, POLARIS_IO_BASE},
124 /* CPUDEP */ {0, 0, 0}, /* for platforms dependent on CPU type */
125 /* PCIDEP */ {0, 0, 0}, /* for platforms dependent on core logic */
128 static struct platform {
132 {"Alcor", IOSYS_CIA},
133 {"Avanti", IOSYS_APECS},
134 {"Cabriolet", IOSYS_APECS},
135 {"EB164", IOSYS_PCIDEP},
136 {"EB64+", IOSYS_APECS},
137 {"EB66", IOSYS_APECS},
138 {"EB66P", IOSYS_APECS},
139 {"Jensen", IOSYS_JENSEN},
140 {"Miata", IOSYS_PYXIS},
141 {"Mikasa", IOSYS_CPUDEP},
142 {"Nautilus", IOSYS_TSUNAMI},
143 {"Noname", IOSYS_APECS},
144 {"Noritake", IOSYS_CPUDEP},
145 {"Rawhide", IOSYS_MCPCIA},
146 {"Ruffian", IOSYS_PYXIS},
147 {"Sable", IOSYS_CPUDEP},
148 {"Takara", IOSYS_CIA},
149 {"Tsunami", IOSYS_TSUNAMI},
154 void (*sethae)(unsigned long int addr);
155 void (*outb)(unsigned char b, unsigned long int port);
156 void (*outw)(unsigned short b, unsigned long int port);
157 void (*outl)(unsigned int b, unsigned long int port);
158 unsigned int (*inb)(unsigned long int port);
159 unsigned int (*inw)(unsigned long int port);
160 unsigned int (*inl)(unsigned long int port);
164 unsigned long int hae_cache;
165 unsigned long int base;
166 struct ioswtch * swp;
167 unsigned long int bus_memory_base;
168 unsigned long int sparse_bus_memory_base;
169 unsigned long int io_base;
174 stb_mb(unsigned char val, unsigned long addr)
176 __asm__("stb %1,%0; mb" : "=m"(*(vucp)addr) : "r"(val));
180 stw_mb(unsigned short val, unsigned long addr)
182 __asm__("stw %1,%0; mb" : "=m"(*(vusp)addr) : "r"(val));
186 stl_mb(unsigned int val, unsigned long addr)
188 __asm__("stl %1,%0; mb" : "=m"(*(vip)addr) : "r"(val));
191 /* No need to examine error -- sethae never fails. */
193 __sethae(unsigned long value)
195 register unsigned long r16 __asm__("$16") = value;
196 register unsigned long r0 __asm__("$0") = __NR_sethae;
197 __asm__ __volatile__ ("callsys"
200 : inline_syscall_clobbers, "$19");
203 extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which,
204 unsigned long int __bus,
205 unsigned long int __dfn);
207 static inline unsigned long int
208 port_to_cpu_addr (unsigned long int port, ioswizzle_t ioswiz, int size)
210 if (ioswiz == IOSWIZZLE_SPARSE)
211 return io.base + (port << 5) + ((size - 1) << 3);
212 else if (ioswiz == IOSWIZZLE_DENSE)
213 return port + io.base;
215 return io.base + (port << 7) + ((size - 1) << 5);
219 inline_sethae (unsigned long int addr, ioswizzle_t ioswiz)
221 if (ioswiz == IOSWIZZLE_SPARSE)
223 unsigned long int msb;
225 /* no need to set hae if msb is 0: */
226 msb = addr & 0xf8000000;
227 if (msb && msb != io.hae_cache)
233 else if (ioswiz == IOSWIZZLE_JENSEN)
235 /* HAE on the Jensen is bits 31:25 shifted right. */
237 if (addr != io.hae_cache)
246 inline_outb (unsigned char b, unsigned long int port, ioswizzle_t ioswiz)
249 unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
251 asm ("insbl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
257 inline_outw (unsigned short int b, unsigned long int port, ioswizzle_t ioswiz)
260 unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
262 asm ("inswl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
268 inline_outl (unsigned int b, unsigned long int port, ioswizzle_t ioswiz)
270 unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
276 static inline unsigned int
277 inline_inb (unsigned long int port, ioswizzle_t ioswiz)
279 unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
282 result = *(vip) addr;
283 result >>= (port & 3) * 8;
284 return 0xffUL & result;
288 static inline unsigned int
289 inline_inw (unsigned long int port, ioswizzle_t ioswiz)
291 unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
294 result = *(vip) addr;
295 result >>= (port & 3) * 8;
296 return 0xffffUL & result;
300 static inline unsigned int
301 inline_inl (unsigned long int port, ioswizzle_t ioswiz)
303 unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
309 * Now define the inline functions for CPUs supporting byte/word insns,
310 * and whose core logic supports I/O space accesses utilizing them.
312 * These routines could be used by MIATA, for example, because it has
313 * and EV56 plus PYXIS, but it currently uses SPARSE anyway. This is
314 * also true of RX164 which used POLARIS, but we will choose to use
315 * these routines in that case instead of SPARSE.
317 * These routines are necessary for TSUNAMI/TYPHOON based platforms,
318 * which will have (at least) EV6.
321 static inline unsigned long int
322 dense_port_to_cpu_addr (unsigned long int port)
324 return port + io.base;
328 inline_bwx_outb (unsigned char b, unsigned long int port)
330 unsigned long int addr = dense_port_to_cpu_addr (port);
335 inline_bwx_outw (unsigned short int b, unsigned long int port)
337 unsigned long int addr = dense_port_to_cpu_addr (port);
342 inline_bwx_outl (unsigned int b, unsigned long int port)
344 unsigned long int addr = dense_port_to_cpu_addr (port);
348 static inline unsigned int
349 inline_bwx_inb (unsigned long int port)
351 unsigned long int addr = dense_port_to_cpu_addr (port);
354 __asm__ ("ldbu %0,%1" : "=r"(r) : "m"(*(vucp)addr));
358 static inline unsigned int
359 inline_bwx_inw (unsigned long int port)
361 unsigned long int addr = dense_port_to_cpu_addr (port);
364 __asm__ ("ldwu %0,%1" : "=r"(r) : "m"(*(vusp)addr));
368 static inline unsigned int
369 inline_bwx_inl (unsigned long int port)
371 unsigned long int addr = dense_port_to_cpu_addr (port);
376 /* macros to define routines with appropriate names and functions */
378 /* these do either SPARSE or JENSEN swizzle */
380 #define DCL_SETHAE(name, ioswiz) \
382 name##_sethae (unsigned long int addr) \
384 inline_sethae (addr, IOSWIZZLE_##ioswiz); \
387 #define DCL_OUT(name, func, type, ioswiz) \
389 name##_##func (unsigned type b, unsigned long int addr) \
391 inline_##func (b, addr, IOSWIZZLE_##ioswiz); \
394 #define DCL_IN(name, func, ioswiz) \
395 static unsigned int \
396 name##_##func (unsigned long int addr) \
398 return inline_##func (addr, IOSWIZZLE_##ioswiz); \
401 /* these do DENSE, so no swizzle is needed */
403 #define DCL_OUT_BWX(name, func, type) \
405 name##_##func (unsigned type b, unsigned long int addr) \
407 inline_bwx_##func (b, addr); \
410 #define DCL_IN_BWX(name, func) \
411 static unsigned int \
412 name##_##func (unsigned long int addr) \
414 return inline_bwx_##func (addr); \
417 /* now declare/define the necessary routines */
419 DCL_SETHAE(jensen, JENSEN)
420 DCL_OUT(jensen, outb, char, JENSEN)
421 DCL_OUT(jensen, outw, short int, JENSEN)
422 DCL_OUT(jensen, outl, int, JENSEN)
423 DCL_IN(jensen, inb, JENSEN)
424 DCL_IN(jensen, inw, JENSEN)
425 DCL_IN(jensen, inl, JENSEN)
427 DCL_SETHAE(sparse, SPARSE)
428 DCL_OUT(sparse, outb, char, SPARSE)
429 DCL_OUT(sparse, outw, short int, SPARSE)
430 DCL_OUT(sparse, outl, int, SPARSE)
431 DCL_IN(sparse, inb, SPARSE)
432 DCL_IN(sparse, inw, SPARSE)
433 DCL_IN(sparse, inl, SPARSE)
435 DCL_SETHAE(dense, DENSE)
436 DCL_OUT_BWX(dense, outb, char)
437 DCL_OUT_BWX(dense, outw, short int)
438 DCL_OUT_BWX(dense, outl, int)
439 DCL_IN_BWX(dense, inb)
440 DCL_IN_BWX(dense, inw)
441 DCL_IN_BWX(dense, inl)
443 /* define the "swizzle" switch */
444 static struct ioswtch ioswtch[] = {
447 jensen_outb, jensen_outw, jensen_outl,
448 jensen_inb, jensen_inw, jensen_inl
452 sparse_outb, sparse_outw, sparse_outl,
453 sparse_inb, sparse_inw, sparse_inl
457 dense_outb, dense_outw, dense_outl,
458 dense_inb, dense_inw, dense_inl
464 /* Routine to process the /proc/cpuinfo information into the fields
465 that are required for correctly determining the platform parameters. */
469 char systype[256]; /* system type field */
470 char sysvari[256]; /* system variation field */
471 char cpumodel[256]; /* cpu model field */
475 process_cpuinfo(struct cpuinfo_data *data)
477 int got_type, got_vari, got_model;
482 data->systype[0] = 0;
483 data->sysvari[0] = 0;
484 data->cpumodel[0] = 0;
486 /* If there's an /etc/alpha_systype link, we're intending to override
487 whatever's in /proc/cpuinfo. */
488 n = __readlink (PATH_ALPHA_SYSTYPE, data->systype, 256 - 1);
491 data->systype[n] = '\0';
495 fp = fopen (PATH_CPUINFO, "r");
499 got_type = got_vari = got_model = 0;
503 if (fgets (dummy, 256, fp) == NULL)
506 sscanf (dummy, "system type : %256[^\n]\n", data->systype) == 1)
509 sscanf (dummy, "system variation : %256[^\n]\n", data->sysvari) == 1)
512 sscanf (dummy, "cpu model : %256[^\n]\n", data->cpumodel) == 1)
519 fprintf(stderr, "system type: `%s'\n", data->systype);
520 fprintf(stderr, "system vari: `%s'\n", data->sysvari);
521 fprintf(stderr, "cpu model: `%s'\n", data->cpumodel);
524 return got_type + got_vari + got_model;
529 * Initialize I/O system.
535 int i, olderrno = errno;
536 struct cpuinfo_data data;
538 /* First try the pciconfig_iobase syscall added to 2.2.15 and 2.3.99. */
540 #ifdef __NR_pciconfig_iobase
541 addr = __pciconfig_iobase (IOBASE_DENSE_MEM, 0, 0);
548 /* Only Jensen doesn't have dense mem space. */
549 io.sparse_bus_memory_base
550 = io_system[IOSYS_JENSEN].sparse_bus_mem_base;
551 io.io_base = io_system[IOSYS_JENSEN].bus_io_base;
552 io_swiz = IOSWIZZLE_JENSEN;
556 io.bus_memory_base = addr;
558 addr = __pciconfig_iobase (IOBASE_DENSE_IO, 0, 0);
561 /* The X server uses _bus_base_sparse == 0 to know that
562 BWX access are supported to dense mem space. This is
563 true of every system that supports dense io space, so
564 never fill in io.sparse_bus_memory_base in this case. */
565 io_swiz = IOSWIZZLE_DENSE;
570 io.sparse_bus_memory_base
571 = __pciconfig_iobase (IOBASE_SPARSE_MEM, 0, 0);
572 io.io_base = __pciconfig_iobase (IOBASE_SPARSE_IO, 0, 0);
573 io_swiz = IOSWIZZLE_SPARSE;
578 io.swp = &ioswtch[io_swiz];
584 /* Second, collect the contents of /etc/alpha_systype or /proc/cpuinfo. */
586 if (process_cpuinfo(&data) == 0)
588 /* This can happen if the format of /proc/cpuinfo changes. */
590 "ioperm.init_iosys: Unable to determine system type.\n"
591 "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
592 __set_errno (ENODEV);
596 /* Translate systype name into i/o system. */
597 for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
599 if (strcmp (platform[i].name, data.systype) == 0)
601 iosys_t io_sys = platform[i].io_sys;
603 /* Some platforms can have either EV4 or EV5 CPUs. */
604 if (io_sys == IOSYS_CPUDEP)
606 /* SABLE or MIKASA or NORITAKE so far. */
607 if (strcmp (platform[i].name, "Sable") == 0)
609 if (strncmp (data.cpumodel, "EV4", 3) == 0)
611 else if (strncmp (data.cpumodel, "EV5", 3) == 0)
612 io_sys = IOSYS_GAMMA;
616 /* This covers MIKASA/NORITAKE. */
617 if (strncmp (data.cpumodel, "EV4", 3) == 0)
618 io_sys = IOSYS_APECS;
619 else if (strncmp (data.cpumodel, "EV5", 3) == 0)
622 if (io_sys == IOSYS_CPUDEP)
624 /* This can happen if the format of /proc/cpuinfo changes.*/
625 fprintf (stderr, "ioperm.init_iosys: Unable to determine"
627 __set_errno (ENODEV);
631 /* Some platforms can have different core logic chipsets */
632 if (io_sys == IOSYS_PCIDEP)
635 if (strcmp (data.systype, "EB164") == 0)
637 if (strncmp (data.sysvari, "RX164", 5) == 0)
638 io_sys = IOSYS_POLARIS;
639 else if (strncmp (data.sysvari, "LX164", 5) == 0
640 || strncmp (data.sysvari, "SX164", 5) == 0)
641 io_sys = IOSYS_PYXIS;
645 if (io_sys == IOSYS_PCIDEP)
647 /* This can happen if the format of /proc/cpuinfo changes.*/
648 fprintf (stderr, "ioperm.init_iosys: Unable to determine"
649 " core logic chipset.\n");
650 __set_errno (ENODEV);
654 io.bus_memory_base = io_system[io_sys].bus_memory_base;
655 io.sparse_bus_memory_base = io_system[io_sys].sparse_bus_mem_base;
656 io.io_base = io_system[io_sys].bus_io_base;
658 if (io_sys == IOSYS_JENSEN)
659 io.swiz = IOSWIZZLE_JENSEN;
660 else if (io_sys == IOSYS_TSUNAMI
661 || io_sys == IOSYS_POLARIS
662 || io_sys == IOSYS_PYXIS)
663 io.swiz = IOSWIZZLE_DENSE;
665 io.swiz = IOSWIZZLE_SPARSE;
666 io.swp = &ioswtch[io.swiz];
668 __set_errno (olderrno);
673 __set_errno (ENODEV);
674 fprintf(stderr, "ioperm.init_iosys: Platform not recognized.\n"
675 "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
681 _ioperm (unsigned long int from, unsigned long int num, int turn_on)
683 unsigned long int addr, len, pagesize = __getpagesize();
686 if (!io.swp && init_iosys() < 0)
689 fprintf(stderr, "ioperm: init_iosys() failed (%m)\n");
694 /* This test isn't as silly as it may look like; consider overflows! */
695 if (from >= MAX_PORT || from + num > MAX_PORT)
697 __set_errno (EINVAL);
699 fprintf(stderr, "ioperm: from/num out of range\n");
705 fprintf(stderr, "ioperm: turn_on %d io.base %ld\n", turn_on, io.base);
715 if (io.swiz != IOSWIZZLE_DENSE)
717 /* Synchronize with hw. */
721 fd = __open ("/dev/mem", O_RDWR);
725 fprintf(stderr, "ioperm: /dev/mem open failed (%m)\n");
730 addr = port_to_cpu_addr (0, io.swiz, 1);
731 len = port_to_cpu_addr (MAX_PORT, io.swiz, 1) - addr;
733 (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED,
737 fprintf(stderr, "ioperm: mmap of len 0x%lx returned 0x%lx\n",
740 if ((long) io.base == -1)
743 prot = PROT_READ | PROT_WRITE;
748 return 0; /* never was turned on... */
750 /* turnoff access to relevant pages: */
753 addr = port_to_cpu_addr (from, io.swiz, 1);
754 addr &= ~(pagesize - 1);
755 len = port_to_cpu_addr (from + num, io.swiz, 1) - addr;
756 return __mprotect ((void *) addr, len, prot);
768 case 1: case 2: case 3:
769 return _ioperm (0, MAX_PORT, 1);
772 __set_errno (EINVAL);
779 _sethae (unsigned long int addr)
781 if (!io.swp && init_iosys () < 0)
784 io.swp->sethae (addr);
789 _outb (unsigned char b, unsigned long int port)
791 if (port >= MAX_PORT)
794 io.swp->outb (b, port);
799 _outw (unsigned short b, unsigned long int port)
801 if (port >= MAX_PORT)
804 io.swp->outw (b, port);
809 _outl (unsigned int b, unsigned long int port)
811 if (port >= MAX_PORT)
814 io.swp->outl (b, port);
819 _inb (unsigned long int port)
821 return io.swp->inb (port);
826 _inw (unsigned long int port)
828 return io.swp->inw (port);
833 _inl (unsigned long int port)
835 return io.swp->inl (port);
842 if (!io.swp && init_iosys () < 0)
844 return io.bus_memory_base;
848 _bus_base_sparse(void)
850 if (!io.swp && init_iosys () < 0)
852 return io.sparse_bus_memory_base;
858 if (!io.swp && init_iosys () < 0)
860 if (io.swiz == IOSWIZZLE_JENSEN)
862 if (io.swiz == IOSWIZZLE_SPARSE)
867 weak_alias (_sethae, sethae);
868 weak_alias (_ioperm, ioperm);
869 weak_alias (_iopl, iopl);
870 weak_alias (_inb, inb);
871 weak_alias (_inw, inw);
872 weak_alias (_inl, inl);
873 weak_alias (_outb, outb);
874 weak_alias (_outw, outw);
875 weak_alias (_outl, outl);
876 weak_alias (_bus_base, bus_base);
877 weak_alias (_bus_base_sparse, bus_base_sparse);
878 weak_alias (_hae_shift, hae_shift);