Back to index

glibc  2.9
ioperm.c
Go to the documentation of this file.
00001 /* Copyright (C) 1992, 1996-1999, 2000 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by David Mosberger.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 /* I/O access is restricted to ISA port space (ports 0..65535).
00021    Modern devices hopefully are sane enough not to put any performance
00022    critical registers in i/o space.
00023 
00024    On the first call to ioperm, the entire (E)ISA port space is mapped
00025    into the virtual address space at address io.base.  mprotect calls
00026    are then used to enable/disable access to ports.  Per page, there
00027    are PAGE_SIZE>>IO_SHIFT I/O ports (e.g., 256 ports on a Low Cost Alpha
00028    based system using 8KB pages).
00029 
00030    Keep in mind that this code should be able to run in a 32bit address
00031    space.  It is therefore unreasonable to expect mmap'ing the entire
00032    sparse address space would work (e.g., the Low Cost Alpha chip has an
00033    I/O address space that's 512MB large!).  */
00034 
00035 /* Make sure the ldbu/stb asms below are not expaneded to macros.  */
00036 #ifndef __alpha_bwx__
00037 asm(".arch ev56");
00038 #endif
00039 
00040 #include <errno.h>
00041 #include <fcntl.h>
00042 #include <stdio.h>
00043 #include <ctype.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <unistd.h>
00047 
00048 #include <sys/types.h>
00049 #include <sys/mman.h>
00050 #include <sys/io.h>
00051 
00052 #include <sysdep.h>
00053 #include <sys/syscall.h>
00054 
00055 #define PATH_ALPHA_SYSTYPE  "/etc/alpha_systype"
00056 #define PATH_CPUINFO        "/proc/cpuinfo"
00057 
00058 #define MAX_PORT     0x10000
00059 #define vip          volatile int *
00060 #define vuip         volatile unsigned int *
00061 #define vusp         volatile unsigned short *
00062 #define vucp         volatile unsigned char *
00063 
00064 #define JENSEN_IO_BASE             (0x300000000UL)
00065 #define JENSEN_SPARSE_MEM   (0x200000000UL)
00066 
00067 /* With respect to the I/O architecture, APECS and LCA are identical,
00068    so the following defines apply to LCA as well.  */
00069 #define APECS_IO_BASE              (0x1c0000000UL)
00070 #define APECS_SPARSE_MEM    (0x200000000UL)
00071 #define APECS_DENSE_MEM            (0x300000000UL)
00072 
00073 /* The same holds for CIA and PYXIS, except for PYXIS we prefer BWX.  */
00074 #define CIA_IO_BASE         (0x8580000000UL)
00075 #define CIA_SPARSE_MEM             (0x8000000000UL)
00076 #define CIA_DENSE_MEM              (0x8600000000UL)
00077 
00078 #define PYXIS_IO_BASE              (0x8900000000UL)
00079 #define PYXIS_DENSE_MEM            (0x8800000000UL)
00080 
00081 /* SABLE is EV4, GAMMA is EV5 */
00082 #define T2_IO_BASE          (0x3a0000000UL)
00083 #define T2_SPARSE_MEM              (0x200000000UL)
00084 #define T2_DENSE_MEM        (0x3c0000000UL)
00085 
00086 #define GAMMA_IO_BASE              (0x83a0000000UL)
00087 #define GAMMA_SPARSE_MEM    (0x8200000000UL)
00088 #define GAMMA_DENSE_MEM            (0x83c0000000UL)
00089 
00090 /* NOTE: these are hardwired to PCI bus 0 addresses!!! */
00091 #define MCPCIA_IO_BASE             (0xf980000000UL)
00092 #define MCPCIA_SPARSE_MEM   (0xf800000000UL)
00093 #define MCPCIA_DENSE_MEM    (0xf900000000UL)
00094 
00095 /* Tsunami and Irongate use the same offsets, at least for hose 0.  */
00096 #define TSUNAMI_IO_BASE            (0x801fc000000UL)
00097 #define TSUNAMI_DENSE_MEM   (0x80000000000UL)
00098 
00099 /* Polaris has SPARSE space, but we prefer to use only DENSE
00100    because of some idiosyncracies in actually using SPARSE.  */
00101 #define POLARIS_IO_BASE            (0xf9fc000000UL)
00102 #define POLARIS_DENSE_MEM   (0xf900000000UL)
00103 
00104 typedef enum {
00105   IOSYS_UNKNOWN, IOSYS_JENSEN, IOSYS_APECS, IOSYS_CIA, IOSYS_PYXIS, IOSYS_T2,
00106   IOSYS_TSUNAMI, IOSYS_MCPCIA, IOSYS_GAMMA, IOSYS_POLARIS,
00107   IOSYS_CPUDEP, IOSYS_PCIDEP
00108 } iosys_t;
00109 
00110 typedef enum {
00111   IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE
00112 } ioswizzle_t;
00113 
00114 static struct io_system {
00115   unsigned long      int bus_memory_base;
00116   unsigned long      int sparse_bus_mem_base;
00117   unsigned long      int bus_io_base;
00118 } io_system[] = { /* NOTE! must match iosys_t enumeration */
00119 /* UNKNOWN */ {0, 0, 0},
00120 /* JENSEN */  {0, JENSEN_SPARSE_MEM, JENSEN_IO_BASE},
00121 /* APECS */   {APECS_DENSE_MEM, APECS_SPARSE_MEM, APECS_IO_BASE},
00122 /* CIA */     {CIA_DENSE_MEM, CIA_SPARSE_MEM, CIA_IO_BASE},
00123 /* PYXIS */   {PYXIS_DENSE_MEM, 0, PYXIS_IO_BASE},
00124 /* T2 */      {T2_DENSE_MEM, T2_SPARSE_MEM, T2_IO_BASE},
00125 /* TSUNAMI */ {TSUNAMI_DENSE_MEM, 0, TSUNAMI_IO_BASE},
00126 /* MCPCIA */  {MCPCIA_DENSE_MEM, MCPCIA_SPARSE_MEM, MCPCIA_IO_BASE},
00127 /* GAMMA */   {GAMMA_DENSE_MEM, GAMMA_SPARSE_MEM, GAMMA_IO_BASE},
00128 /* POLARIS */ {POLARIS_DENSE_MEM, 0, POLARIS_IO_BASE},
00129 /* CPUDEP */  {0, 0, 0}, /* for platforms dependent on CPU type */
00130 /* PCIDEP */  {0, 0, 0}, /* for platforms dependent on core logic */
00131 };
00132 
00133 static struct platform {
00134   const char     *name;
00135   iosys_t         io_sys;
00136 } platform[] = {
00137   {"Alcor",   IOSYS_CIA},
00138   {"Avanti",  IOSYS_APECS},
00139   {"Cabriolet",      IOSYS_APECS},
00140   {"EB164",   IOSYS_PCIDEP},
00141   {"EB64+",   IOSYS_APECS},
00142   {"EB66",    IOSYS_APECS},
00143   {"EB66P",   IOSYS_APECS},
00144   {"Jensen",  IOSYS_JENSEN},
00145   {"Miata",   IOSYS_PYXIS},
00146   {"Mikasa",  IOSYS_CPUDEP},
00147   {"Nautilus",       IOSYS_TSUNAMI},
00148   {"Noname",  IOSYS_APECS},
00149   {"Noritake",       IOSYS_CPUDEP},
00150   {"Rawhide", IOSYS_MCPCIA},
00151   {"Ruffian", IOSYS_PYXIS},
00152   {"Sable",   IOSYS_CPUDEP},
00153   {"Takara",  IOSYS_CIA},
00154   {"Tsunami", IOSYS_TSUNAMI},
00155   {"XL",      IOSYS_APECS},
00156 };
00157 
00158 struct ioswtch {
00159   void        (*sethae)(unsigned long int addr);
00160   void        (*outb)(unsigned char b, unsigned long int port);
00161   void        (*outw)(unsigned short b, unsigned long int port);
00162   void        (*outl)(unsigned int b, unsigned long int port);
00163   unsigned int       (*inb)(unsigned long int port);
00164   unsigned int       (*inw)(unsigned long int port);
00165   unsigned int       (*inl)(unsigned long int port);
00166 };
00167 
00168 static struct {
00169   unsigned long int hae_cache;
00170   unsigned long int  base;
00171   struct ioswtch *   swp;
00172   unsigned long int  bus_memory_base;
00173   unsigned long int  sparse_bus_memory_base;
00174   unsigned long int  io_base;
00175   ioswizzle_t        swiz;
00176 } io;
00177 
00178 static inline void
00179 stb_mb(unsigned char val, unsigned long addr)
00180 {
00181   __asm__("stb %1,%0; mb" : "=m"(*(vucp)addr) : "r"(val));
00182 }
00183 
00184 static inline void
00185 stw_mb(unsigned short val, unsigned long addr)
00186 {
00187   __asm__("stw %1,%0; mb" : "=m"(*(vusp)addr) : "r"(val));
00188 }
00189 
00190 static inline void
00191 stl_mb(unsigned int val, unsigned long addr)
00192 {
00193   __asm__("stl %1,%0; mb" : "=m"(*(vip)addr) : "r"(val));
00194 }
00195 
00196 /* No need to examine error -- sethae never fails.  */
00197 static inline void
00198 __sethae(unsigned long value)
00199 {
00200   register unsigned long r16 __asm__("$16") = value;
00201   register unsigned long r0 __asm__("$0") = __NR_sethae;
00202   __asm__ __volatile__ ("callsys"
00203                      : "=r"(r0)
00204                      : "0"(r0), "r" (r16)
00205                      : inline_syscall_clobbers, "$19");
00206 }
00207 
00208 extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which,
00209                             unsigned long int __bus,
00210                             unsigned long int __dfn);
00211 
00212 static inline unsigned long int
00213 port_to_cpu_addr (unsigned long int port, ioswizzle_t ioswiz, int size)
00214 {
00215   if (ioswiz == IOSWIZZLE_SPARSE)
00216     return io.base + (port << 5) + ((size - 1) << 3);
00217   else if (ioswiz == IOSWIZZLE_DENSE)
00218     return port + io.base;
00219   else
00220     return io.base + (port << 7) + ((size - 1) << 5);
00221 }
00222 
00223 static inline void
00224 inline_sethae (unsigned long int addr, ioswizzle_t ioswiz)
00225 {
00226   if (ioswiz == IOSWIZZLE_SPARSE)
00227     {
00228       unsigned long int msb;
00229 
00230       /* no need to set hae if msb is 0: */
00231       msb = addr & 0xf8000000;
00232       if (msb && msb != io.hae_cache)
00233        {
00234          io.hae_cache = msb;
00235          __sethae (msb);
00236        }
00237     }
00238   else if (ioswiz == IOSWIZZLE_JENSEN)
00239     {
00240       /* HAE on the Jensen is bits 31:25 shifted right.  */
00241       addr >>= 25;
00242       if (addr != io.hae_cache)
00243        {
00244          io.hae_cache = addr;
00245          __sethae (addr);
00246        }
00247     }
00248 }
00249 
00250 static inline void
00251 inline_outb (unsigned char b, unsigned long int port, ioswizzle_t ioswiz)
00252 {
00253   unsigned int w;
00254   unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
00255 
00256   asm ("insbl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
00257   stl_mb(w, addr);
00258 }
00259 
00260 
00261 static inline void
00262 inline_outw (unsigned short int b, unsigned long int port, ioswizzle_t ioswiz)
00263 {
00264   unsigned long w;
00265   unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
00266 
00267   asm ("inswl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
00268   stl_mb(w, addr);
00269 }
00270 
00271 
00272 static inline void
00273 inline_outl (unsigned int b, unsigned long int port, ioswizzle_t ioswiz)
00274 {
00275   unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
00276 
00277   stl_mb(b, addr);
00278 }
00279 
00280 
00281 static inline unsigned int
00282 inline_inb (unsigned long int port, ioswizzle_t ioswiz)
00283 {
00284   unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
00285   int result;
00286 
00287   result = *(vip) addr;
00288   result >>= (port & 3) * 8;
00289   return 0xffUL & result;
00290 }
00291 
00292 
00293 static inline unsigned int
00294 inline_inw (unsigned long int port, ioswizzle_t ioswiz)
00295 {
00296   unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
00297   int result;
00298 
00299   result = *(vip) addr;
00300   result >>= (port & 3) * 8;
00301   return 0xffffUL & result;
00302 }
00303 
00304 
00305 static inline unsigned int
00306 inline_inl (unsigned long int port, ioswizzle_t ioswiz)
00307 {
00308   unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
00309 
00310   return *(vuip) addr;
00311 }
00312 
00313 /*
00314  * Now define the inline functions for CPUs supporting byte/word insns,
00315  * and whose core logic supports I/O space accesses utilizing them.
00316  *
00317  * These routines could be used by MIATA, for example, because it has
00318  * and EV56 plus PYXIS, but it currently uses SPARSE anyway. This is
00319  * also true of RX164 which used POLARIS, but we will choose to use
00320  * these routines in that case instead of SPARSE.
00321  *
00322  * These routines are necessary for TSUNAMI/TYPHOON based platforms,
00323  * which will have (at least) EV6.
00324  */
00325 
00326 static inline unsigned long int
00327 dense_port_to_cpu_addr (unsigned long int port)
00328 {
00329   return port + io.base;
00330 }
00331 
00332 static inline void
00333 inline_bwx_outb (unsigned char b, unsigned long int port)
00334 {
00335   unsigned long int addr = dense_port_to_cpu_addr (port);
00336   stb_mb (b, addr);
00337 }
00338 
00339 static inline void
00340 inline_bwx_outw (unsigned short int b, unsigned long int port)
00341 {
00342   unsigned long int addr = dense_port_to_cpu_addr (port);
00343   stw_mb (b, addr);
00344 }
00345 
00346 static inline void
00347 inline_bwx_outl (unsigned int b, unsigned long int port)
00348 {
00349   unsigned long int addr = dense_port_to_cpu_addr (port);
00350   stl_mb (b, addr);
00351 }
00352 
00353 static inline unsigned int
00354 inline_bwx_inb (unsigned long int port)
00355 {
00356   unsigned long int addr = dense_port_to_cpu_addr (port);
00357   unsigned char r;
00358 
00359   __asm__ ("ldbu %0,%1" : "=r"(r) : "m"(*(vucp)addr));
00360   return r;
00361 }
00362 
00363 static inline unsigned int
00364 inline_bwx_inw (unsigned long int port)
00365 {
00366   unsigned long int addr = dense_port_to_cpu_addr (port);
00367   unsigned short r;
00368 
00369   __asm__ ("ldwu %0,%1" : "=r"(r) : "m"(*(vusp)addr));
00370   return r;
00371 }
00372 
00373 static inline unsigned int
00374 inline_bwx_inl (unsigned long int port)
00375 {
00376   unsigned long int addr = dense_port_to_cpu_addr (port);
00377 
00378   return *(vuip) addr;
00379 }
00380 
00381 /* macros to define routines with appropriate names and functions */
00382 
00383 /* these do either SPARSE or JENSEN swizzle */
00384 
00385 #define DCL_SETHAE(name, ioswiz)                        \
00386 static void                                             \
00387 name##_sethae (unsigned long int addr)                  \
00388 {                                                       \
00389   inline_sethae (addr, IOSWIZZLE_##ioswiz);             \
00390 }
00391 
00392 #define DCL_OUT(name, func, type, ioswiz)        \
00393 static void                                      \
00394 name##_##func (unsigned type b, unsigned long int addr) \
00395 {                                                \
00396   inline_##func (b, addr, IOSWIZZLE_##ioswiz);          \
00397 }
00398 
00399 #define DCL_IN(name, func, ioswiz)               \
00400 static unsigned int                              \
00401 name##_##func (unsigned long int addr)                  \
00402 {                                                \
00403   return inline_##func (addr, IOSWIZZLE_##ioswiz);      \
00404 }
00405 
00406 /* these do DENSE, so no swizzle is needed */
00407 
00408 #define DCL_OUT_BWX(name, func, type)                   \
00409 static void                                      \
00410 name##_##func (unsigned type b, unsigned long int addr) \
00411 {                                                \
00412   inline_bwx_##func (b, addr);                          \
00413 }
00414 
00415 #define DCL_IN_BWX(name, func)                          \
00416 static unsigned int                              \
00417 name##_##func (unsigned long int addr)                  \
00418 {                                                \
00419   return inline_bwx_##func (addr);               \
00420 }
00421 
00422 /* now declare/define the necessary routines */
00423 
00424 DCL_SETHAE(jensen, JENSEN)
00425 DCL_OUT(jensen, outb, char,  JENSEN)
00426 DCL_OUT(jensen, outw, short int, JENSEN)
00427 DCL_OUT(jensen, outl, int,   JENSEN)
00428 DCL_IN(jensen, inb, JENSEN)
00429 DCL_IN(jensen, inw, JENSEN)
00430 DCL_IN(jensen, inl, JENSEN)
00431 
00432 DCL_SETHAE(sparse, SPARSE)
00433 DCL_OUT(sparse, outb, char,  SPARSE)
00434 DCL_OUT(sparse, outw, short int, SPARSE)
00435 DCL_OUT(sparse, outl, int,   SPARSE)
00436 DCL_IN(sparse, inb, SPARSE)
00437 DCL_IN(sparse, inw, SPARSE)
00438 DCL_IN(sparse, inl, SPARSE)
00439 
00440 DCL_SETHAE(dense, DENSE)
00441 DCL_OUT_BWX(dense, outb, char)
00442 DCL_OUT_BWX(dense, outw, short int)
00443 DCL_OUT_BWX(dense, outl, int)
00444 DCL_IN_BWX(dense, inb)
00445 DCL_IN_BWX(dense, inw)
00446 DCL_IN_BWX(dense, inl)
00447 
00448 /* define the "swizzle" switch */
00449 static struct ioswtch ioswtch[] = {
00450   {
00451     jensen_sethae,
00452     jensen_outb, jensen_outw, jensen_outl,
00453     jensen_inb, jensen_inw, jensen_inl
00454   },
00455   {
00456     sparse_sethae,
00457     sparse_outb, sparse_outw, sparse_outl,
00458     sparse_inb, sparse_inw, sparse_inl
00459   },
00460   {
00461     dense_sethae,
00462     dense_outb, dense_outw, dense_outl,
00463     dense_inb, dense_inw, dense_inl
00464   }
00465 };
00466 
00467 #undef DEBUG_IOPERM
00468 
00469 /* Routine to process the /proc/cpuinfo information into the fields
00470    that are required for correctly determining the platform parameters.  */
00471 
00472 struct cpuinfo_data
00473 {
00474   char systype[256];        /* system type field */
00475   char sysvari[256];        /* system variation field */
00476   char cpumodel[256];              /* cpu model field */
00477 };
00478 
00479 static inline int
00480 process_cpuinfo(struct cpuinfo_data *data)
00481 {
00482   int got_type, got_vari, got_model;
00483   char dummy[256];
00484   FILE * fp;
00485   int n;
00486 
00487   data->systype[0] = 0;
00488   data->sysvari[0] = 0;
00489   data->cpumodel[0] = 0;
00490 
00491   /* If there's an /etc/alpha_systype link, we're intending to override
00492      whatever's in /proc/cpuinfo.  */
00493   n = __readlink (PATH_ALPHA_SYSTYPE, data->systype, 256 - 1);
00494   if (n > 0)
00495     {
00496       data->systype[n] = '\0';
00497       return 1;
00498     }
00499 
00500   fp = fopen (PATH_CPUINFO, "r");
00501   if (!fp)
00502     return 0;
00503 
00504   got_type = got_vari = got_model = 0;
00505 
00506   while (1)
00507     {
00508       if (fgets (dummy, 256, fp) == NULL)
00509        break;
00510       if (!got_type &&
00511          sscanf (dummy, "system type : %256[^\n]\n", data->systype) == 1)
00512        got_type = 1;
00513       if (!got_vari &&
00514          sscanf (dummy, "system variation : %256[^\n]\n", data->sysvari) == 1)
00515        got_vari = 1;
00516       if (!got_model &&
00517          sscanf (dummy, "cpu model : %256[^\n]\n", data->cpumodel) == 1)
00518        got_model = 1;
00519     }
00520 
00521   fclose (fp);
00522 
00523 #ifdef DEBUG_IOPERM
00524   fprintf(stderr, "system type: `%s'\n", data->systype);
00525   fprintf(stderr, "system vari: `%s'\n", data->sysvari);
00526   fprintf(stderr, "cpu model: `%s'\n", data->cpumodel);
00527 #endif
00528 
00529   return got_type + got_vari + got_model;
00530 }
00531 
00532 
00533 /*
00534  * Initialize I/O system.
00535  */
00536 static int
00537 init_iosys (void)
00538 {
00539   long addr;
00540   int i, olderrno = errno;
00541   struct cpuinfo_data data;
00542 
00543   /* First try the pciconfig_iobase syscall added to 2.2.15 and 2.3.99.  */
00544 
00545 #ifdef __NR_pciconfig_iobase
00546   addr = __pciconfig_iobase (IOBASE_DENSE_MEM, 0, 0);
00547   if (addr != -1)
00548     {
00549       ioswizzle_t io_swiz;
00550 
00551       if (addr == 0)
00552         {
00553          /* Only Jensen doesn't have dense mem space.  */
00554          io.sparse_bus_memory_base
00555            = io_system[IOSYS_JENSEN].sparse_bus_mem_base;
00556          io.io_base = io_system[IOSYS_JENSEN].bus_io_base;
00557          io_swiz = IOSWIZZLE_JENSEN;
00558        }
00559       else
00560        {
00561          io.bus_memory_base = addr;
00562 
00563          addr = __pciconfig_iobase (IOBASE_DENSE_IO, 0, 0);
00564          if (addr != 0)
00565            {
00566              /* The X server uses _bus_base_sparse == 0 to know that
00567                BWX access are supported to dense mem space.  This is
00568                true of every system that supports dense io space, so
00569                 never fill in io.sparse_bus_memory_base in this case.  */
00570              io_swiz = IOSWIZZLE_DENSE;
00571               io.io_base = addr;
00572            }
00573          else
00574            {
00575              io.sparse_bus_memory_base
00576               = __pciconfig_iobase (IOBASE_SPARSE_MEM, 0, 0);
00577              io.io_base = __pciconfig_iobase (IOBASE_SPARSE_IO, 0, 0);
00578              io_swiz = IOSWIZZLE_SPARSE;
00579            }
00580        }
00581 
00582       io.swiz = io_swiz;
00583       io.swp = &ioswtch[io_swiz];
00584 
00585       return 0;
00586     }
00587 #endif
00588 
00589   /* Second, collect the contents of /etc/alpha_systype or /proc/cpuinfo.  */
00590 
00591   if (process_cpuinfo(&data) == 0)
00592     {
00593       /* This can happen if the format of /proc/cpuinfo changes.  */
00594       fprintf (stderr,
00595               "ioperm.init_iosys: Unable to determine system type.\n"
00596               "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
00597       __set_errno (ENODEV);
00598       return -1;
00599     }
00600 
00601   /* Translate systype name into i/o system.  */
00602   for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
00603     {
00604       if (strcmp (platform[i].name, data.systype) == 0)
00605        {
00606          iosys_t io_sys = platform[i].io_sys;
00607 
00608          /* Some platforms can have either EV4 or EV5 CPUs.  */
00609          if (io_sys == IOSYS_CPUDEP)
00610            {
00611              /* SABLE or MIKASA or NORITAKE so far.  */
00612              if (strcmp (platform[i].name, "Sable") == 0)
00613               {
00614                 if (strncmp (data.cpumodel, "EV4", 3) == 0)
00615                   io_sys = IOSYS_T2;
00616                 else if (strncmp (data.cpumodel, "EV5", 3) == 0)
00617                   io_sys = IOSYS_GAMMA;
00618               }
00619              else
00620               {
00621                 /* This covers MIKASA/NORITAKE.  */
00622                 if (strncmp (data.cpumodel, "EV4", 3) == 0)
00623                   io_sys = IOSYS_APECS;
00624                 else if (strncmp (data.cpumodel, "EV5", 3) == 0)
00625                   io_sys = IOSYS_CIA;
00626               }
00627              if (io_sys == IOSYS_CPUDEP)
00628               {
00629                 /* This can happen if the format of /proc/cpuinfo changes.*/
00630                 fprintf (stderr, "ioperm.init_iosys: Unable to determine"
00631                         " CPU model.\n");
00632                 __set_errno (ENODEV);
00633                 return -1;
00634               }
00635            }
00636          /* Some platforms can have different core logic chipsets */
00637          if (io_sys == IOSYS_PCIDEP)
00638            {
00639              /* EB164 so far */
00640              if (strcmp (data.systype, "EB164") == 0)
00641               {
00642                 if (strncmp (data.sysvari, "RX164", 5) == 0)
00643                   io_sys = IOSYS_POLARIS;
00644                 else if (strncmp (data.sysvari, "LX164", 5) == 0
00645                         || strncmp (data.sysvari, "SX164", 5) == 0)
00646                   io_sys = IOSYS_PYXIS;
00647                 else
00648                   io_sys = IOSYS_CIA;
00649               }
00650              if (io_sys == IOSYS_PCIDEP)
00651               {
00652                 /* This can happen if the format of /proc/cpuinfo changes.*/
00653                 fprintf (stderr, "ioperm.init_iosys: Unable to determine"
00654                         " core logic chipset.\n");
00655                 __set_errno (ENODEV);
00656                 return -1;
00657               }
00658            }
00659          io.bus_memory_base = io_system[io_sys].bus_memory_base;
00660          io.sparse_bus_memory_base = io_system[io_sys].sparse_bus_mem_base;
00661          io.io_base = io_system[io_sys].bus_io_base;
00662 
00663          if (io_sys == IOSYS_JENSEN)
00664            io.swiz = IOSWIZZLE_JENSEN;
00665          else if (io_sys == IOSYS_TSUNAMI
00666                  || io_sys == IOSYS_POLARIS
00667                  || io_sys == IOSYS_PYXIS)
00668            io.swiz = IOSWIZZLE_DENSE;
00669          else
00670            io.swiz = IOSWIZZLE_SPARSE;
00671          io.swp = &ioswtch[io.swiz];
00672 
00673          __set_errno (olderrno);
00674          return 0;
00675        }
00676     }
00677 
00678   __set_errno (ENODEV);
00679   fprintf(stderr, "ioperm.init_iosys: Platform not recognized.\n"
00680          "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
00681   return -1;
00682 }
00683 
00684 
00685 int
00686 _ioperm (unsigned long int from, unsigned long int num, int turn_on)
00687 {
00688   unsigned long int addr, len, pagesize = __getpagesize();
00689   int prot;
00690 
00691   if (!io.swp && init_iosys() < 0)
00692     {
00693 #ifdef DEBUG_IOPERM
00694       fprintf(stderr, "ioperm: init_iosys() failed (%m)\n");
00695 #endif
00696       return -1;
00697     }
00698 
00699   /* This test isn't as silly as it may look like; consider overflows! */
00700   if (from >= MAX_PORT || from + num > MAX_PORT)
00701     {
00702       __set_errno (EINVAL);
00703 #ifdef DEBUG_IOPERM
00704       fprintf(stderr, "ioperm: from/num out of range\n");
00705 #endif
00706       return -1;
00707     }
00708 
00709 #ifdef DEBUG_IOPERM
00710   fprintf(stderr, "ioperm: turn_on %d io.base %ld\n", turn_on, io.base);
00711 #endif
00712 
00713   if (turn_on)
00714     {
00715       if (!io.base)
00716        {
00717          int fd;
00718 
00719          io.hae_cache = 0;
00720          if (io.swiz != IOSWIZZLE_DENSE)
00721            {
00722              /* Synchronize with hw.  */
00723              __sethae (0);
00724            }
00725 
00726          fd = __open ("/dev/mem", O_RDWR);
00727          if (fd < 0)
00728            {
00729 #ifdef DEBUG_IOPERM
00730              fprintf(stderr, "ioperm: /dev/mem open failed (%m)\n");
00731 #endif
00732              return -1;
00733            }
00734 
00735          addr = port_to_cpu_addr (0, io.swiz, 1);
00736          len = port_to_cpu_addr (MAX_PORT, io.swiz, 1) - addr;
00737          io.base =
00738            (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED,
00739                                    fd, io.io_base);
00740          __close (fd);
00741 #ifdef DEBUG_IOPERM
00742          fprintf(stderr, "ioperm: mmap of len 0x%lx  returned 0x%lx\n",
00743                 len, io.base);
00744 #endif
00745          if ((long) io.base == -1)
00746            return -1;
00747        }
00748       prot = PROT_READ | PROT_WRITE;
00749     }
00750   else
00751     {
00752       if (!io.base)
00753        return 0;     /* never was turned on... */
00754 
00755       /* turnoff access to relevant pages: */
00756       prot = PROT_NONE;
00757     }
00758   addr = port_to_cpu_addr (from, io.swiz, 1);
00759   addr &= ~(pagesize - 1);
00760   len = port_to_cpu_addr (from + num, io.swiz, 1) - addr;
00761   return __mprotect ((void *) addr, len, prot);
00762 }
00763 
00764 
00765 int
00766 _iopl (int level)
00767 {
00768   switch (level)
00769     {
00770     case 0:
00771       return 0;
00772 
00773     case 1: case 2: case 3:
00774       return _ioperm (0, MAX_PORT, 1);
00775 
00776     default:
00777       __set_errno (EINVAL);
00778       return -1;
00779     }
00780 }
00781 
00782 
00783 void
00784 _sethae (unsigned long int addr)
00785 {
00786   if (!io.swp && init_iosys () < 0)
00787     return;
00788 
00789   io.swp->sethae (addr);
00790 }
00791 
00792 
00793 void
00794 _outb (unsigned char b, unsigned long int port)
00795 {
00796   if (port >= MAX_PORT)
00797     return;
00798 
00799   io.swp->outb (b, port);
00800 }
00801 
00802 
00803 void
00804 _outw (unsigned short b, unsigned long int port)
00805 {
00806   if (port >= MAX_PORT)
00807     return;
00808 
00809   io.swp->outw (b, port);
00810 }
00811 
00812 
00813 void
00814 _outl (unsigned int b, unsigned long int port)
00815 {
00816   if (port >= MAX_PORT)
00817     return;
00818 
00819   io.swp->outl (b, port);
00820 }
00821 
00822 
00823 unsigned int
00824 _inb (unsigned long int port)
00825 {
00826   return io.swp->inb (port);
00827 }
00828 
00829 
00830 unsigned int
00831 _inw (unsigned long int port)
00832 {
00833   return io.swp->inw (port);
00834 }
00835 
00836 
00837 unsigned int
00838 _inl (unsigned long int port)
00839 {
00840   return io.swp->inl (port);
00841 }
00842 
00843 
00844 unsigned long int
00845 _bus_base(void)
00846 {
00847   if (!io.swp && init_iosys () < 0)
00848     return -1;
00849   return io.bus_memory_base;
00850 }
00851 
00852 unsigned long int
00853 _bus_base_sparse(void)
00854 {
00855   if (!io.swp && init_iosys () < 0)
00856     return -1;
00857   return io.sparse_bus_memory_base;
00858 }
00859 
00860 int
00861 _hae_shift(void)
00862 {
00863   if (!io.swp && init_iosys () < 0)
00864     return -1;
00865   if (io.swiz == IOSWIZZLE_JENSEN)
00866     return 7;
00867   if (io.swiz == IOSWIZZLE_SPARSE)
00868     return 5;
00869   return 0;
00870 }
00871 
00872 weak_alias (_sethae, sethae);
00873 weak_alias (_ioperm, ioperm);
00874 weak_alias (_iopl, iopl);
00875 weak_alias (_inb, inb);
00876 weak_alias (_inw, inw);
00877 weak_alias (_inl, inl);
00878 weak_alias (_outb, outb);
00879 weak_alias (_outw, outw);
00880 weak_alias (_outl, outl);
00881 weak_alias (_bus_base, bus_base);
00882 weak_alias (_bus_base_sparse, bus_base_sparse);
00883 weak_alias (_hae_shift, hae_shift);