Blame sysdeps/unix/sysv/linux/alpha/ioperm.c

Packit 6c4009
/* Copyright (C) 1992-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by David Mosberger.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library.  If not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* I/O access is restricted to ISA port space (ports 0..65535).
Packit 6c4009
   Modern devices hopefully are sane enough not to put any performance
Packit 6c4009
   critical registers in i/o space.
Packit 6c4009
Packit 6c4009
   On the first call to ioperm, the entire (E)ISA port space is mapped
Packit 6c4009
   into the virtual address space at address io.base.  mprotect calls
Packit 6c4009
   are then used to enable/disable access to ports.  Per page, there
Packit 6c4009
   are PAGE_SIZE>>IO_SHIFT I/O ports (e.g., 256 ports on a Low Cost Alpha
Packit 6c4009
   based system using 8KB pages).
Packit 6c4009
Packit 6c4009
   Keep in mind that this code should be able to run in a 32bit address
Packit 6c4009
   space.  It is therefore unreasonable to expect mmap'ing the entire
Packit 6c4009
   sparse address space would work (e.g., the Low Cost Alpha chip has an
Packit 6c4009
   I/O address space that's 512MB large!).  */
Packit 6c4009
Packit 6c4009
/* Make sure the ldbu/stb asms below are not expaneded to macros.  */
Packit 6c4009
#ifndef __alpha_bwx__
Packit 6c4009
asm(".arch ev56");
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <sys/mman.h>
Packit 6c4009
#include <sys/io.h>
Packit 6c4009
Packit 6c4009
#include <sysdep.h>
Packit 6c4009
#include <sys/syscall.h>
Packit 6c4009
Packit 6c4009
#define PATH_ALPHA_SYSTYPE	"/etc/alpha_systype"
Packit 6c4009
#define PATH_CPUINFO		"/proc/cpuinfo"
Packit 6c4009
Packit 6c4009
#define MAX_PORT	0x10000
Packit 6c4009
#define vip		volatile int *
Packit 6c4009
#define vuip		volatile unsigned int *
Packit 6c4009
#define vusp		volatile unsigned short *
Packit 6c4009
#define vucp		volatile unsigned char *
Packit 6c4009
Packit 6c4009
#define JENSEN_IO_BASE		(0x300000000UL)
Packit 6c4009
#define JENSEN_SPARSE_MEM	(0x200000000UL)
Packit 6c4009
Packit 6c4009
/* With respect to the I/O architecture, APECS and LCA are identical,
Packit 6c4009
   so the following defines apply to LCA as well.  */
Packit 6c4009
#define APECS_IO_BASE		(0x1c0000000UL)
Packit 6c4009
#define APECS_SPARSE_MEM	(0x200000000UL)
Packit 6c4009
#define APECS_DENSE_MEM		(0x300000000UL)
Packit 6c4009
Packit 6c4009
/* The same holds for CIA and PYXIS, except for PYXIS we prefer BWX.  */
Packit 6c4009
#define CIA_IO_BASE		(0x8580000000UL)
Packit 6c4009
#define CIA_SPARSE_MEM		(0x8000000000UL)
Packit 6c4009
#define CIA_DENSE_MEM		(0x8600000000UL)
Packit 6c4009
Packit 6c4009
#define PYXIS_IO_BASE		(0x8900000000UL)
Packit 6c4009
#define PYXIS_DENSE_MEM		(0x8800000000UL)
Packit 6c4009
Packit 6c4009
/* SABLE is EV4, GAMMA is EV5 */
Packit 6c4009
#define T2_IO_BASE		(0x3a0000000UL)
Packit 6c4009
#define T2_SPARSE_MEM		(0x200000000UL)
Packit 6c4009
#define T2_DENSE_MEM		(0x3c0000000UL)
Packit 6c4009
Packit 6c4009
#define GAMMA_IO_BASE		(0x83a0000000UL)
Packit 6c4009
#define GAMMA_SPARSE_MEM	(0x8200000000UL)
Packit 6c4009
#define GAMMA_DENSE_MEM		(0x83c0000000UL)
Packit 6c4009
Packit 6c4009
/* NOTE: these are hardwired to PCI bus 0 addresses!!! */
Packit 6c4009
#define MCPCIA_IO_BASE		(0xf980000000UL)
Packit 6c4009
#define MCPCIA_SPARSE_MEM	(0xf800000000UL)
Packit 6c4009
#define MCPCIA_DENSE_MEM	(0xf900000000UL)
Packit 6c4009
Packit 6c4009
/* Tsunami and Irongate use the same offsets, at least for hose 0.  */
Packit 6c4009
#define TSUNAMI_IO_BASE		(0x801fc000000UL)
Packit 6c4009
#define TSUNAMI_DENSE_MEM	(0x80000000000UL)
Packit 6c4009
Packit 6c4009
/* Polaris has SPARSE space, but we prefer to use only DENSE
Packit 6c4009
   because of some idiosyncracies in actually using SPARSE.  */
Packit 6c4009
#define POLARIS_IO_BASE		(0xf9fc000000UL)
Packit 6c4009
#define POLARIS_DENSE_MEM	(0xf900000000UL)
Packit 6c4009
Packit 6c4009
typedef enum {
Packit 6c4009
  IOSYS_UNKNOWN, IOSYS_JENSEN, IOSYS_APECS, IOSYS_CIA, IOSYS_PYXIS, IOSYS_T2,
Packit 6c4009
  IOSYS_TSUNAMI, IOSYS_MCPCIA, IOSYS_GAMMA, IOSYS_POLARIS,
Packit 6c4009
  IOSYS_CPUDEP, IOSYS_PCIDEP
Packit 6c4009
} iosys_t;
Packit 6c4009
Packit 6c4009
typedef enum {
Packit 6c4009
  IOSWIZZLE_JENSEN, IOSWIZZLE_SPARSE, IOSWIZZLE_DENSE
Packit 6c4009
} ioswizzle_t;
Packit 6c4009
Packit 6c4009
static struct io_system {
Packit 6c4009
  unsigned long	int bus_memory_base;
Packit 6c4009
  unsigned long	int sparse_bus_mem_base;
Packit 6c4009
  unsigned long	int bus_io_base;
Packit 6c4009
} io_system[] = { /* NOTE! must match iosys_t enumeration */
Packit 6c4009
/* UNKNOWN */	{0, 0, 0},
Packit 6c4009
/* JENSEN */	{0, JENSEN_SPARSE_MEM, JENSEN_IO_BASE},
Packit 6c4009
/* APECS */	{APECS_DENSE_MEM, APECS_SPARSE_MEM, APECS_IO_BASE},
Packit 6c4009
/* CIA */	{CIA_DENSE_MEM, CIA_SPARSE_MEM, CIA_IO_BASE},
Packit 6c4009
/* PYXIS */	{PYXIS_DENSE_MEM, 0, PYXIS_IO_BASE},
Packit 6c4009
/* T2 */	{T2_DENSE_MEM, T2_SPARSE_MEM, T2_IO_BASE},
Packit 6c4009
/* TSUNAMI */	{TSUNAMI_DENSE_MEM, 0, TSUNAMI_IO_BASE},
Packit 6c4009
/* MCPCIA */	{MCPCIA_DENSE_MEM, MCPCIA_SPARSE_MEM, MCPCIA_IO_BASE},
Packit 6c4009
/* GAMMA */	{GAMMA_DENSE_MEM, GAMMA_SPARSE_MEM, GAMMA_IO_BASE},
Packit 6c4009
/* POLARIS */	{POLARIS_DENSE_MEM, 0, POLARIS_IO_BASE},
Packit 6c4009
/* CPUDEP */	{0, 0, 0}, /* for platforms dependent on CPU type */
Packit 6c4009
/* PCIDEP */	{0, 0, 0}, /* for platforms dependent on core logic */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static struct platform {
Packit 6c4009
  const char	   *name;
Packit 6c4009
  iosys_t	    io_sys;
Packit 6c4009
} platform[] = {
Packit 6c4009
  {"Alcor",	IOSYS_CIA},
Packit 6c4009
  {"Avanti",	IOSYS_APECS},
Packit 6c4009
  {"Cabriolet",	IOSYS_APECS},
Packit 6c4009
  {"EB164",	IOSYS_PCIDEP},
Packit 6c4009
  {"EB64+",	IOSYS_APECS},
Packit 6c4009
  {"EB66",	IOSYS_APECS},
Packit 6c4009
  {"EB66P",	IOSYS_APECS},
Packit 6c4009
  {"Jensen",	IOSYS_JENSEN},
Packit 6c4009
  {"Miata",	IOSYS_PYXIS},
Packit 6c4009
  {"Mikasa",	IOSYS_CPUDEP},
Packit 6c4009
  {"Nautilus",	IOSYS_TSUNAMI},
Packit 6c4009
  {"Noname",	IOSYS_APECS},
Packit 6c4009
  {"Noritake",	IOSYS_CPUDEP},
Packit 6c4009
  {"Rawhide",	IOSYS_MCPCIA},
Packit 6c4009
  {"Ruffian",	IOSYS_PYXIS},
Packit 6c4009
  {"Sable",	IOSYS_CPUDEP},
Packit 6c4009
  {"Takara",	IOSYS_CIA},
Packit 6c4009
  {"Tsunami",	IOSYS_TSUNAMI},
Packit 6c4009
  {"XL",	IOSYS_APECS},
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
struct ioswtch {
Packit 6c4009
  void		(*sethae)(unsigned long int addr);
Packit 6c4009
  void		(*outb)(unsigned char b, unsigned long int port);
Packit 6c4009
  void		(*outw)(unsigned short b, unsigned long int port);
Packit 6c4009
  void		(*outl)(unsigned int b, unsigned long int port);
Packit 6c4009
  unsigned int	(*inb)(unsigned long int port);
Packit 6c4009
  unsigned int	(*inw)(unsigned long int port);
Packit 6c4009
  unsigned int	(*inl)(unsigned long int port);
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static struct {
Packit 6c4009
  unsigned long int hae_cache;
Packit 6c4009
  unsigned long int	base;
Packit 6c4009
  struct ioswtch *	swp;
Packit 6c4009
  unsigned long int	bus_memory_base;
Packit 6c4009
  unsigned long int	sparse_bus_memory_base;
Packit 6c4009
  unsigned long int	io_base;
Packit 6c4009
  ioswizzle_t		swiz;
Packit 6c4009
} io;
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
stb_mb(unsigned char val, unsigned long addr)
Packit 6c4009
{
Packit 6c4009
  __asm__("stb %1,%0; mb" : "=m"(*(vucp)addr) : "r"(val));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
stw_mb(unsigned short val, unsigned long addr)
Packit 6c4009
{
Packit 6c4009
  __asm__("stw %1,%0; mb" : "=m"(*(vusp)addr) : "r"(val));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
stl_mb(unsigned int val, unsigned long addr)
Packit 6c4009
{
Packit 6c4009
  __asm__("stl %1,%0; mb" : "=m"(*(vip)addr) : "r"(val));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* No need to examine error -- sethae never fails.  */
Packit 6c4009
static inline void
Packit 6c4009
__sethae(unsigned long value)
Packit 6c4009
{
Packit 6c4009
  register unsigned long r16 __asm__("$16") = value;
Packit 6c4009
  register unsigned long r0 __asm__("$0") = __NR_sethae;
Packit 6c4009
  __asm__ __volatile__ ("callsys"
Packit 6c4009
			: "=r"(r0)
Packit 6c4009
			: "0"(r0), "r" (r16)
Packit 6c4009
			: inline_syscall_clobbers, "$19");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
extern long __pciconfig_iobase(enum __pciconfig_iobase_which __which,
Packit 6c4009
			       unsigned long int __bus,
Packit 6c4009
			       unsigned long int __dfn);
Packit 6c4009
Packit 6c4009
static inline unsigned long int
Packit 6c4009
port_to_cpu_addr (unsigned long int port, ioswizzle_t ioswiz, int size)
Packit 6c4009
{
Packit 6c4009
  if (ioswiz == IOSWIZZLE_SPARSE)
Packit 6c4009
    return io.base + (port << 5) + ((size - 1) << 3);
Packit 6c4009
  else if (ioswiz == IOSWIZZLE_DENSE)
Packit 6c4009
    return port + io.base;
Packit 6c4009
  else
Packit 6c4009
    return io.base + (port << 7) + ((size - 1) << 5);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline __attribute__((always_inline)) void
Packit 6c4009
inline_sethae (unsigned long int addr, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  if (ioswiz == IOSWIZZLE_SPARSE)
Packit 6c4009
    {
Packit 6c4009
      unsigned long int msb;
Packit 6c4009
Packit 6c4009
      /* no need to set hae if msb is 0: */
Packit 6c4009
      msb = addr & 0xf8000000;
Packit 6c4009
      if (msb && msb != io.hae_cache)
Packit 6c4009
	{
Packit 6c4009
	  io.hae_cache = msb;
Packit 6c4009
	  __sethae (msb);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else if (ioswiz == IOSWIZZLE_JENSEN)
Packit 6c4009
    {
Packit 6c4009
      /* HAE on the Jensen is bits 31:25 shifted right.  */
Packit 6c4009
      addr >>= 25;
Packit 6c4009
      if (addr != io.hae_cache)
Packit 6c4009
	{
Packit 6c4009
	  io.hae_cache = addr;
Packit 6c4009
	  __sethae (addr);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
inline_outb (unsigned char b, unsigned long int port, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  unsigned int w;
Packit 6c4009
  unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
Packit 6c4009
Packit 6c4009
  asm ("insbl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
Packit 6c4009
  stl_mb(w, addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
inline_outw (unsigned short int b, unsigned long int port, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  unsigned long w;
Packit 6c4009
  unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
Packit 6c4009
Packit 6c4009
  asm ("inswl %2,%1,%0" : "=r" (w) : "ri" (port & 0x3), "r" (b));
Packit 6c4009
  stl_mb(w, addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
inline_outl (unsigned int b, unsigned long int port, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
Packit 6c4009
Packit 6c4009
  stl_mb(b, addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
inline_inb (unsigned long int port, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = port_to_cpu_addr (port, ioswiz, 1);
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  result = *(vip) addr;
Packit 6c4009
  result >>= (port & 3) * 8;
Packit 6c4009
  return 0xffUL & result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
inline_inw (unsigned long int port, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = port_to_cpu_addr (port, ioswiz, 2);
Packit 6c4009
  int result;
Packit 6c4009
Packit 6c4009
  result = *(vip) addr;
Packit 6c4009
  result >>= (port & 3) * 8;
Packit 6c4009
  return 0xffffUL & result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
inline_inl (unsigned long int port, ioswizzle_t ioswiz)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = port_to_cpu_addr (port, ioswiz, 4);
Packit 6c4009
Packit 6c4009
  return *(vuip) addr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Now define the inline functions for CPUs supporting byte/word insns,
Packit 6c4009
 * and whose core logic supports I/O space accesses utilizing them.
Packit 6c4009
 *
Packit 6c4009
 * These routines could be used by MIATA, for example, because it has
Packit 6c4009
 * and EV56 plus PYXIS, but it currently uses SPARSE anyway. This is
Packit 6c4009
 * also true of RX164 which used POLARIS, but we will choose to use
Packit 6c4009
 * these routines in that case instead of SPARSE.
Packit 6c4009
 *
Packit 6c4009
 * These routines are necessary for TSUNAMI/TYPHOON based platforms,
Packit 6c4009
 * which will have (at least) EV6.
Packit 6c4009
 */
Packit 6c4009
Packit 6c4009
static inline unsigned long int
Packit 6c4009
dense_port_to_cpu_addr (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  return port + io.base;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
inline_bwx_outb (unsigned char b, unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = dense_port_to_cpu_addr (port);
Packit 6c4009
  stb_mb (b, addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
inline_bwx_outw (unsigned short int b, unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = dense_port_to_cpu_addr (port);
Packit 6c4009
  stw_mb (b, addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline void
Packit 6c4009
inline_bwx_outl (unsigned int b, unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = dense_port_to_cpu_addr (port);
Packit 6c4009
  stl_mb (b, addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
inline_bwx_inb (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = dense_port_to_cpu_addr (port);
Packit 6c4009
  unsigned char r;
Packit 6c4009
Packit 6c4009
  __asm__ ("ldbu %0,%1" : "=r"(r) : "m"(*(vucp)addr));
Packit 6c4009
  return r;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
inline_bwx_inw (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = dense_port_to_cpu_addr (port);
Packit 6c4009
  unsigned short r;
Packit 6c4009
Packit 6c4009
  __asm__ ("ldwu %0,%1" : "=r"(r) : "m"(*(vusp)addr));
Packit 6c4009
  return r;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static inline unsigned int
Packit 6c4009
inline_bwx_inl (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr = dense_port_to_cpu_addr (port);
Packit 6c4009
Packit 6c4009
  return *(vuip) addr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* macros to define routines with appropriate names and functions */
Packit 6c4009
Packit 6c4009
/* these do either SPARSE or JENSEN swizzle */
Packit 6c4009
Packit 6c4009
#define DCL_SETHAE(name, ioswiz)                        \
Packit 6c4009
static void                                             \
Packit 6c4009
name##_sethae (unsigned long int addr)                  \
Packit 6c4009
{                                                       \
Packit 6c4009
  inline_sethae (addr, IOSWIZZLE_##ioswiz);             \
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define DCL_OUT(name, func, type, ioswiz)		\
Packit 6c4009
static void						\
Packit 6c4009
name##_##func (unsigned type b, unsigned long int addr)	\
Packit 6c4009
{							\
Packit 6c4009
  inline_##func (b, addr, IOSWIZZLE_##ioswiz);		\
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define DCL_IN(name, func, ioswiz)			\
Packit 6c4009
static unsigned int					\
Packit 6c4009
name##_##func (unsigned long int addr)			\
Packit 6c4009
{							\
Packit 6c4009
  return inline_##func (addr, IOSWIZZLE_##ioswiz);	\
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* these do DENSE, so no swizzle is needed */
Packit 6c4009
Packit 6c4009
#define DCL_OUT_BWX(name, func, type)			\
Packit 6c4009
static void						\
Packit 6c4009
name##_##func (unsigned type b, unsigned long int addr)	\
Packit 6c4009
{							\
Packit 6c4009
  inline_bwx_##func (b, addr);				\
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define DCL_IN_BWX(name, func)				\
Packit 6c4009
static unsigned int					\
Packit 6c4009
name##_##func (unsigned long int addr)			\
Packit 6c4009
{							\
Packit 6c4009
  return inline_bwx_##func (addr);			\
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* now declare/define the necessary routines */
Packit 6c4009
Packit 6c4009
DCL_SETHAE(jensen, JENSEN)
Packit 6c4009
DCL_OUT(jensen, outb, char,  JENSEN)
Packit 6c4009
DCL_OUT(jensen, outw, short int, JENSEN)
Packit 6c4009
DCL_OUT(jensen, outl, int,   JENSEN)
Packit 6c4009
DCL_IN(jensen, inb, JENSEN)
Packit 6c4009
DCL_IN(jensen, inw, JENSEN)
Packit 6c4009
DCL_IN(jensen, inl, JENSEN)
Packit 6c4009
Packit 6c4009
DCL_SETHAE(sparse, SPARSE)
Packit 6c4009
DCL_OUT(sparse, outb, char,  SPARSE)
Packit 6c4009
DCL_OUT(sparse, outw, short int, SPARSE)
Packit 6c4009
DCL_OUT(sparse, outl, int,   SPARSE)
Packit 6c4009
DCL_IN(sparse, inb, SPARSE)
Packit 6c4009
DCL_IN(sparse, inw, SPARSE)
Packit 6c4009
DCL_IN(sparse, inl, SPARSE)
Packit 6c4009
Packit 6c4009
DCL_SETHAE(dense, DENSE)
Packit 6c4009
DCL_OUT_BWX(dense, outb, char)
Packit 6c4009
DCL_OUT_BWX(dense, outw, short int)
Packit 6c4009
DCL_OUT_BWX(dense, outl, int)
Packit 6c4009
DCL_IN_BWX(dense, inb)
Packit 6c4009
DCL_IN_BWX(dense, inw)
Packit 6c4009
DCL_IN_BWX(dense, inl)
Packit 6c4009
Packit 6c4009
/* define the "swizzle" switch */
Packit 6c4009
static struct ioswtch ioswtch[] = {
Packit 6c4009
  {
Packit 6c4009
    jensen_sethae,
Packit 6c4009
    jensen_outb, jensen_outw, jensen_outl,
Packit 6c4009
    jensen_inb, jensen_inw, jensen_inl
Packit 6c4009
  },
Packit 6c4009
  {
Packit 6c4009
    sparse_sethae,
Packit 6c4009
    sparse_outb, sparse_outw, sparse_outl,
Packit 6c4009
    sparse_inb, sparse_inw, sparse_inl
Packit 6c4009
  },
Packit 6c4009
  {
Packit 6c4009
    dense_sethae,
Packit 6c4009
    dense_outb, dense_outw, dense_outl,
Packit 6c4009
    dense_inb, dense_inw, dense_inl
Packit 6c4009
  }
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
#undef DEBUG_IOPERM
Packit 6c4009
Packit 6c4009
/* Routine to process the /proc/cpuinfo information into the fields
Packit 6c4009
   that are required for correctly determining the platform parameters.  */
Packit 6c4009
Packit 6c4009
struct cpuinfo_data
Packit 6c4009
{
Packit 6c4009
  char systype[256];		/* system type field */
Packit 6c4009
  char sysvari[256];		/* system variation field */
Packit 6c4009
  char cpumodel[256];		/* cpu model field */
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static inline int
Packit 6c4009
process_cpuinfo(struct cpuinfo_data *data)
Packit 6c4009
{
Packit 6c4009
  int got_type, got_vari, got_model;
Packit 6c4009
  char dummy[256];
Packit 6c4009
  FILE * fp;
Packit 6c4009
  int n;
Packit 6c4009
Packit 6c4009
  data->systype[0] = 0;
Packit 6c4009
  data->sysvari[0] = 0;
Packit 6c4009
  data->cpumodel[0] = 0;
Packit 6c4009
Packit 6c4009
  /* If there's an /etc/alpha_systype link, we're intending to override
Packit 6c4009
     whatever's in /proc/cpuinfo.  */
Packit 6c4009
  n = __readlink (PATH_ALPHA_SYSTYPE, data->systype, 256 - 1);
Packit 6c4009
  if (n > 0)
Packit 6c4009
    {
Packit 6c4009
      data->systype[n] = '\0';
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fp = fopen (PATH_CPUINFO, "rce");
Packit 6c4009
  if (!fp)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  got_type = got_vari = got_model = 0;
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      if (fgets_unlocked (dummy, 256, fp) == NULL)
Packit 6c4009
	break;
Packit 6c4009
      if (!got_type &&
Packit 6c4009
	  sscanf (dummy, "system type : %256[^\n]\n", data->systype) == 1)
Packit 6c4009
	got_type = 1;
Packit 6c4009
      if (!got_vari &&
Packit 6c4009
	  sscanf (dummy, "system variation : %256[^\n]\n", data->sysvari) == 1)
Packit 6c4009
	got_vari = 1;
Packit 6c4009
      if (!got_model &&
Packit 6c4009
	  sscanf (dummy, "cpu model : %256[^\n]\n", data->cpumodel) == 1)
Packit 6c4009
	got_model = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fclose (fp);
Packit 6c4009
Packit 6c4009
#ifdef DEBUG_IOPERM
Packit 6c4009
  fprintf(stderr, "system type: `%s'\n", data->systype);
Packit 6c4009
  fprintf(stderr, "system vari: `%s'\n", data->sysvari);
Packit 6c4009
  fprintf(stderr, "cpu model: `%s'\n", data->cpumodel);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  return got_type + got_vari + got_model;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Initialize I/O system.
Packit 6c4009
 */
Packit 6c4009
static int
Packit 6c4009
init_iosys (void)
Packit 6c4009
{
Packit 6c4009
  long addr;
Packit 6c4009
  int i, olderrno = errno;
Packit 6c4009
  struct cpuinfo_data data;
Packit 6c4009
Packit 6c4009
  /* First try the pciconfig_iobase syscall added to 2.2.15 and 2.3.99.  */
Packit 6c4009
Packit 6c4009
#ifdef __NR_pciconfig_iobase
Packit 6c4009
  addr = __pciconfig_iobase (IOBASE_DENSE_MEM, 0, 0);
Packit 6c4009
  if (addr != -1)
Packit 6c4009
    {
Packit 6c4009
      ioswizzle_t io_swiz;
Packit 6c4009
Packit 6c4009
      if (addr == 0)
Packit 6c4009
        {
Packit 6c4009
	  /* Only Jensen doesn't have dense mem space.  */
Packit 6c4009
	  io.sparse_bus_memory_base
Packit 6c4009
	    = io_system[IOSYS_JENSEN].sparse_bus_mem_base;
Packit 6c4009
	  io.io_base = io_system[IOSYS_JENSEN].bus_io_base;
Packit 6c4009
	  io_swiz = IOSWIZZLE_JENSEN;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  io.bus_memory_base = addr;
Packit 6c4009
Packit 6c4009
	  addr = __pciconfig_iobase (IOBASE_DENSE_IO, 0, 0);
Packit 6c4009
	  if (addr != 0)
Packit 6c4009
	    {
Packit 6c4009
	      /* The X server uses _bus_base_sparse == 0 to know that
Packit 6c4009
		 BWX access are supported to dense mem space.  This is
Packit 6c4009
		 true of every system that supports dense io space, so
Packit 6c4009
	         never fill in io.sparse_bus_memory_base in this case.  */
Packit 6c4009
	      io_swiz = IOSWIZZLE_DENSE;
Packit 6c4009
              io.io_base = addr;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      io.sparse_bus_memory_base
Packit 6c4009
		= __pciconfig_iobase (IOBASE_SPARSE_MEM, 0, 0);
Packit 6c4009
	      io.io_base = __pciconfig_iobase (IOBASE_SPARSE_IO, 0, 0);
Packit 6c4009
	      io_swiz = IOSWIZZLE_SPARSE;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      io.swiz = io_swiz;
Packit 6c4009
      io.swp = &ioswtch[io_swiz];
Packit 6c4009
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  /* Second, collect the contents of /etc/alpha_systype or /proc/cpuinfo.  */
Packit 6c4009
Packit 6c4009
  if (process_cpuinfo(&data) == 0)
Packit 6c4009
    {
Packit 6c4009
      /* This can happen if the format of /proc/cpuinfo changes.  */
Packit 6c4009
      fprintf (stderr,
Packit 6c4009
	       "ioperm.init_iosys: Unable to determine system type.\n"
Packit 6c4009
	       "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
Packit 6c4009
      __set_errno (ENODEV);
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Translate systype name into i/o system.  */
Packit 6c4009
  for (i = 0; i < sizeof (platform) / sizeof (platform[0]); ++i)
Packit 6c4009
    {
Packit 6c4009
      if (strcmp (platform[i].name, data.systype) == 0)
Packit 6c4009
	{
Packit 6c4009
	  iosys_t io_sys = platform[i].io_sys;
Packit 6c4009
Packit 6c4009
	  /* Some platforms can have either EV4 or EV5 CPUs.  */
Packit 6c4009
	  if (io_sys == IOSYS_CPUDEP)
Packit 6c4009
	    {
Packit 6c4009
	      /* SABLE or MIKASA or NORITAKE so far.  */
Packit 6c4009
	      if (strcmp (platform[i].name, "Sable") == 0)
Packit 6c4009
		{
Packit 6c4009
		  if (strncmp (data.cpumodel, "EV4", 3) == 0)
Packit 6c4009
		    io_sys = IOSYS_T2;
Packit 6c4009
		  else if (strncmp (data.cpumodel, "EV5", 3) == 0)
Packit 6c4009
		    io_sys = IOSYS_GAMMA;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		{
Packit 6c4009
		  /* This covers MIKASA/NORITAKE.  */
Packit 6c4009
		  if (strncmp (data.cpumodel, "EV4", 3) == 0)
Packit 6c4009
		    io_sys = IOSYS_APECS;
Packit 6c4009
		  else if (strncmp (data.cpumodel, "EV5", 3) == 0)
Packit 6c4009
		    io_sys = IOSYS_CIA;
Packit 6c4009
		}
Packit 6c4009
	      if (io_sys == IOSYS_CPUDEP)
Packit 6c4009
		{
Packit 6c4009
		  /* This can happen if the format of /proc/cpuinfo changes.*/
Packit 6c4009
		  fprintf (stderr, "ioperm.init_iosys: Unable to determine"
Packit 6c4009
			   " CPU model.\n");
Packit 6c4009
		  __set_errno (ENODEV);
Packit 6c4009
		  return -1;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  /* Some platforms can have different core logic chipsets */
Packit 6c4009
	  if (io_sys == IOSYS_PCIDEP)
Packit 6c4009
	    {
Packit 6c4009
	      /* EB164 so far */
Packit 6c4009
	      if (strcmp (data.systype, "EB164") == 0)
Packit 6c4009
		{
Packit 6c4009
		  if (strncmp (data.sysvari, "RX164", 5) == 0)
Packit 6c4009
		    io_sys = IOSYS_POLARIS;
Packit 6c4009
		  else if (strncmp (data.sysvari, "LX164", 5) == 0
Packit 6c4009
			   || strncmp (data.sysvari, "SX164", 5) == 0)
Packit 6c4009
		    io_sys = IOSYS_PYXIS;
Packit 6c4009
		  else
Packit 6c4009
		    io_sys = IOSYS_CIA;
Packit 6c4009
		}
Packit 6c4009
	      if (io_sys == IOSYS_PCIDEP)
Packit 6c4009
		{
Packit 6c4009
		  /* This can happen if the format of /proc/cpuinfo changes.*/
Packit 6c4009
		  fprintf (stderr, "ioperm.init_iosys: Unable to determine"
Packit 6c4009
			   " core logic chipset.\n");
Packit 6c4009
		  __set_errno (ENODEV);
Packit 6c4009
		  return -1;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  io.bus_memory_base = io_system[io_sys].bus_memory_base;
Packit 6c4009
	  io.sparse_bus_memory_base = io_system[io_sys].sparse_bus_mem_base;
Packit 6c4009
	  io.io_base = io_system[io_sys].bus_io_base;
Packit 6c4009
Packit 6c4009
	  if (io_sys == IOSYS_JENSEN)
Packit 6c4009
	    io.swiz = IOSWIZZLE_JENSEN;
Packit 6c4009
	  else if (io_sys == IOSYS_TSUNAMI
Packit 6c4009
		   || io_sys == IOSYS_POLARIS
Packit 6c4009
		   || io_sys == IOSYS_PYXIS)
Packit 6c4009
	    io.swiz = IOSWIZZLE_DENSE;
Packit 6c4009
	  else
Packit 6c4009
	    io.swiz = IOSWIZZLE_SPARSE;
Packit 6c4009
	  io.swp = &ioswtch[io.swiz];
Packit 6c4009
Packit 6c4009
	  __set_errno (olderrno);
Packit 6c4009
	  return 0;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __set_errno (ENODEV);
Packit 6c4009
  fprintf(stderr, "ioperm.init_iosys: Platform not recognized.\n"
Packit 6c4009
	  "\t(May need " PATH_ALPHA_SYSTYPE " symlink?)\n");
Packit 6c4009
  return -1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_ioperm (unsigned long int from, unsigned long int num, int turn_on)
Packit 6c4009
{
Packit 6c4009
  unsigned long int addr, len, pagesize = __getpagesize();
Packit 6c4009
  int prot;
Packit 6c4009
Packit 6c4009
  if (!io.swp && init_iosys() < 0)
Packit 6c4009
    {
Packit 6c4009
#ifdef DEBUG_IOPERM
Packit 6c4009
      fprintf(stderr, "ioperm: init_iosys() failed (%m)\n");
Packit 6c4009
#endif
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* This test isn't as silly as it may look like; consider overflows! */
Packit 6c4009
  if (from >= MAX_PORT || from + num > MAX_PORT)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
#ifdef DEBUG_IOPERM
Packit 6c4009
      fprintf(stderr, "ioperm: from/num out of range\n");
Packit 6c4009
#endif
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#ifdef DEBUG_IOPERM
Packit 6c4009
  fprintf(stderr, "ioperm: turn_on %d io.base %ld\n", turn_on, io.base);
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  if (turn_on)
Packit 6c4009
    {
Packit 6c4009
      if (!io.base)
Packit 6c4009
	{
Packit 6c4009
	  int fd;
Packit 6c4009
Packit 6c4009
	  io.hae_cache = 0;
Packit 6c4009
	  if (io.swiz != IOSWIZZLE_DENSE)
Packit 6c4009
	    {
Packit 6c4009
	      /* Synchronize with hw.  */
Packit 6c4009
	      __sethae (0);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  fd = __open ("/dev/mem", O_RDWR);
Packit 6c4009
	  if (fd < 0)
Packit 6c4009
	    {
Packit 6c4009
#ifdef DEBUG_IOPERM
Packit 6c4009
	      fprintf(stderr, "ioperm: /dev/mem open failed (%m)\n");
Packit 6c4009
#endif
Packit 6c4009
	      return -1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  addr = port_to_cpu_addr (0, io.swiz, 1);
Packit 6c4009
	  len = port_to_cpu_addr (MAX_PORT, io.swiz, 1) - addr;
Packit 6c4009
	  io.base =
Packit 6c4009
	    (unsigned long int) __mmap (0, len, PROT_NONE, MAP_SHARED,
Packit 6c4009
					fd, io.io_base);
Packit 6c4009
	  __close (fd);
Packit 6c4009
#ifdef DEBUG_IOPERM
Packit 6c4009
	  fprintf(stderr, "ioperm: mmap of len 0x%lx  returned 0x%lx\n",
Packit 6c4009
		  len, io.base);
Packit 6c4009
#endif
Packit 6c4009
	  if ((long) io.base == -1)
Packit 6c4009
	    return -1;
Packit 6c4009
	}
Packit 6c4009
      prot = PROT_READ | PROT_WRITE;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      if (!io.base)
Packit 6c4009
	return 0;	/* never was turned on... */
Packit 6c4009
Packit 6c4009
      /* turnoff access to relevant pages: */
Packit 6c4009
      prot = PROT_NONE;
Packit 6c4009
    }
Packit 6c4009
  addr = port_to_cpu_addr (from, io.swiz, 1);
Packit 6c4009
  addr &= ~(pagesize - 1);
Packit 6c4009
  len = port_to_cpu_addr (from + num, io.swiz, 1) - addr;
Packit 6c4009
  return __mprotect ((void *) addr, len, prot);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_iopl (int level)
Packit 6c4009
{
Packit 6c4009
  switch (level)
Packit 6c4009
    {
Packit 6c4009
    case 0:
Packit 6c4009
      return 0;
Packit 6c4009
Packit 6c4009
    case 1: case 2: case 3:
Packit 6c4009
      return _ioperm (0, MAX_PORT, 1);
Packit 6c4009
Packit 6c4009
    default:
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_sethae (unsigned long int addr)
Packit 6c4009
{
Packit 6c4009
  if (!io.swp && init_iosys () < 0)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  io.swp->sethae (addr);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_outb (unsigned char b, unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  if (port >= MAX_PORT)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  io.swp->outb (b, port);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_outw (unsigned short b, unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  if (port >= MAX_PORT)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  io.swp->outw (b, port);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_outl (unsigned int b, unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  if (port >= MAX_PORT)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  io.swp->outl (b, port);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
unsigned int
Packit 6c4009
_inb (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  return io.swp->inb (port);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
unsigned int
Packit 6c4009
_inw (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  return io.swp->inw (port);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
unsigned int
Packit 6c4009
_inl (unsigned long int port)
Packit 6c4009
{
Packit 6c4009
  return io.swp->inl (port);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
unsigned long int
Packit 6c4009
_bus_base(void)
Packit 6c4009
{
Packit 6c4009
  if (!io.swp && init_iosys () < 0)
Packit 6c4009
    return -1;
Packit 6c4009
  return io.bus_memory_base;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
unsigned long int
Packit 6c4009
_bus_base_sparse(void)
Packit 6c4009
{
Packit 6c4009
  if (!io.swp && init_iosys () < 0)
Packit 6c4009
    return -1;
Packit 6c4009
  return io.sparse_bus_memory_base;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
_hae_shift(void)
Packit 6c4009
{
Packit 6c4009
  if (!io.swp && init_iosys () < 0)
Packit 6c4009
    return -1;
Packit 6c4009
  if (io.swiz == IOSWIZZLE_JENSEN)
Packit 6c4009
    return 7;
Packit 6c4009
  if (io.swiz == IOSWIZZLE_SPARSE)
Packit 6c4009
    return 5;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
weak_alias (_sethae, sethae);
Packit 6c4009
weak_alias (_ioperm, ioperm);
Packit 6c4009
weak_alias (_iopl, iopl);
Packit 6c4009
weak_alias (_inb, inb);
Packit 6c4009
weak_alias (_inw, inw);
Packit 6c4009
weak_alias (_inl, inl);
Packit 6c4009
weak_alias (_outb, outb);
Packit 6c4009
weak_alias (_outw, outw);
Packit 6c4009
weak_alias (_outl, outl);
Packit 6c4009
weak_alias (_bus_base, bus_base);
Packit 6c4009
weak_alias (_bus_base_sparse, bus_base_sparse);
Packit 6c4009
weak_alias (_hae_shift, hae_shift);