xref: /openbmc/linux/arch/alpha/kernel/core_irongate.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *	linux/arch/alpha/kernel/core_irongate.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com).
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *	Copyright (C) 1999 Alpha Processor, Inc.,
81da177e4SLinus Torvalds  *		(David Daniel, Stig Telfer, Soohoon Lee)
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Code common to all IRONGATE core logic chips.
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #define __EXTERN_INLINE inline
141da177e4SLinus Torvalds #include <asm/io.h>
151da177e4SLinus Torvalds #include <asm/core_irongate.h>
161da177e4SLinus Torvalds #undef __EXTERN_INLINE
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/types.h>
191da177e4SLinus Torvalds #include <linux/pci.h>
201da177e4SLinus Torvalds #include <linux/sched.h>
211da177e4SLinus Torvalds #include <linux/init.h>
221da177e4SLinus Torvalds #include <linux/initrd.h>
236471f52aSMike Rapoport #include <linux/memblock.h>
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <asm/ptrace.h>
261da177e4SLinus Torvalds #include <asm/cacheflush.h>
271da177e4SLinus Torvalds #include <asm/tlbflush.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include "proto.h"
301da177e4SLinus Torvalds #include "pci_impl.h"
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds /*
331da177e4SLinus Torvalds  * BIOS32-style PCI interface:
341da177e4SLinus Torvalds  */
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #define DEBUG_CONFIG 0
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #if DEBUG_CONFIG
391da177e4SLinus Torvalds # define DBG_CFG(args)	printk args
401da177e4SLinus Torvalds #else
411da177e4SLinus Torvalds # define DBG_CFG(args)
421da177e4SLinus Torvalds #endif
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds igcsr32 *IronECC;
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds /*
471da177e4SLinus Torvalds  * Given a bus, device, and function number, compute resulting
481da177e4SLinus Torvalds  * configuration space address accordingly.  It is therefore not safe
491da177e4SLinus Torvalds  * to have concurrent invocations to configuration space access
501da177e4SLinus Torvalds  * routines, but there really shouldn't be any need for this.
511da177e4SLinus Torvalds  *
521da177e4SLinus Torvalds  *	addr[31:24]		reserved
531da177e4SLinus Torvalds  *	addr[23:16]		bus number (8 bits = 128 possible buses)
541da177e4SLinus Torvalds  *	addr[15:11]		Device number (5 bits)
551da177e4SLinus Torvalds  *	addr[10: 8]		function number
561da177e4SLinus Torvalds  *	addr[ 7: 2]		register number
571da177e4SLinus Torvalds  *
581da177e4SLinus Torvalds  * For IRONGATE:
591da177e4SLinus Torvalds  *    if (bus = addr[23:16]) == 0
601da177e4SLinus Torvalds  *    then
611da177e4SLinus Torvalds  *	  type 0 config cycle:
621da177e4SLinus Torvalds  *	      addr_on_pci[31:11] = id selection for device = addr[15:11]
631da177e4SLinus Torvalds  *	      addr_on_pci[10: 2] = addr[10: 2] ???
641da177e4SLinus Torvalds  *	      addr_on_pci[ 1: 0] = 00
651da177e4SLinus Torvalds  *    else
661da177e4SLinus Torvalds  *	  type 1 config cycle (pass on with no decoding):
671da177e4SLinus Torvalds  *	      addr_on_pci[31:24] = 0
681da177e4SLinus Torvalds  *	      addr_on_pci[23: 2] = addr[23: 2]
691da177e4SLinus Torvalds  *	      addr_on_pci[ 1: 0] = 01
701da177e4SLinus Torvalds  *    fi
711da177e4SLinus Torvalds  *
721da177e4SLinus Torvalds  * Notes:
731da177e4SLinus Torvalds  *	The function number selects which function of a multi-function device
741da177e4SLinus Torvalds  *	(e.g., SCSI and Ethernet).
751da177e4SLinus Torvalds  *
761da177e4SLinus Torvalds  *	The register selects a DWORD (32 bit) register offset.	Hence it
771da177e4SLinus Torvalds  *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
781da177e4SLinus Torvalds  *	bits.
791da177e4SLinus Torvalds  */
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds static int
mk_conf_addr(struct pci_bus * pbus,unsigned int device_fn,int where,unsigned long * pci_addr,unsigned char * type1)821da177e4SLinus Torvalds mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
831da177e4SLinus Torvalds 	     unsigned long *pci_addr, unsigned char *type1)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	unsigned long addr;
861da177e4SLinus Torvalds 	u8 bus = pbus->number;
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds 	DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, "
891da177e4SLinus Torvalds 		 "pci_addr=0x%p, type1=0x%p)\n",
901da177e4SLinus Torvalds 		 bus, device_fn, where, pci_addr, type1));
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	*type1 = (bus != 0);
931da177e4SLinus Torvalds 
941da177e4SLinus Torvalds 	addr = (bus << 16) | (device_fn << 8) | where;
951da177e4SLinus Torvalds 	addr |= IRONGATE_CONF;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	*pci_addr = addr;
981da177e4SLinus Torvalds 	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
991da177e4SLinus Torvalds 	return 0;
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds static int
irongate_read_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 * value)1031da177e4SLinus Torvalds irongate_read_config(struct pci_bus *bus, unsigned int devfn, int where,
1041da177e4SLinus Torvalds 		     int size, u32 *value)
1051da177e4SLinus Torvalds {
1061da177e4SLinus Torvalds 	unsigned long addr;
1071da177e4SLinus Torvalds 	unsigned char type1;
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 	if (mk_conf_addr(bus, devfn, where, &addr, &type1))
1101da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds 	switch (size) {
1131da177e4SLinus Torvalds 	case 1:
1141da177e4SLinus Torvalds 		*value = __kernel_ldbu(*(vucp)addr);
1151da177e4SLinus Torvalds 		break;
1161da177e4SLinus Torvalds 	case 2:
1171da177e4SLinus Torvalds 		*value = __kernel_ldwu(*(vusp)addr);
1181da177e4SLinus Torvalds 		break;
1191da177e4SLinus Torvalds 	case 4:
1201da177e4SLinus Torvalds 		*value = *(vuip)addr;
1211da177e4SLinus Torvalds 		break;
1221da177e4SLinus Torvalds 	}
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds static int
irongate_write_config(struct pci_bus * bus,unsigned int devfn,int where,int size,u32 value)1281da177e4SLinus Torvalds irongate_write_config(struct pci_bus *bus, unsigned int devfn, int where,
1291da177e4SLinus Torvalds 		      int size, u32 value)
1301da177e4SLinus Torvalds {
1311da177e4SLinus Torvalds 	unsigned long addr;
1321da177e4SLinus Torvalds 	unsigned char type1;
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds 	if (mk_conf_addr(bus, devfn, where, &addr, &type1))
1351da177e4SLinus Torvalds 		return PCIBIOS_DEVICE_NOT_FOUND;
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds 	switch (size) {
1381da177e4SLinus Torvalds 	case 1:
1391da177e4SLinus Torvalds 		__kernel_stb(value, *(vucp)addr);
1401da177e4SLinus Torvalds 		mb();
1411da177e4SLinus Torvalds 		__kernel_ldbu(*(vucp)addr);
1421da177e4SLinus Torvalds 		break;
1431da177e4SLinus Torvalds 	case 2:
1441da177e4SLinus Torvalds 		__kernel_stw(value, *(vusp)addr);
1451da177e4SLinus Torvalds 		mb();
1461da177e4SLinus Torvalds 		__kernel_ldwu(*(vusp)addr);
1471da177e4SLinus Torvalds 		break;
1481da177e4SLinus Torvalds 	case 4:
1491da177e4SLinus Torvalds 		*(vuip)addr = value;
1501da177e4SLinus Torvalds 		mb();
1511da177e4SLinus Torvalds 		*(vuip)addr;
1521da177e4SLinus Torvalds 		break;
1531da177e4SLinus Torvalds 	}
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	return PCIBIOS_SUCCESSFUL;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds struct pci_ops irongate_pci_ops =
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	.read =		irongate_read_config,
1611da177e4SLinus Torvalds 	.write =	irongate_write_config,
1621da177e4SLinus Torvalds };
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds int
irongate_pci_clr_err(void)1651da177e4SLinus Torvalds irongate_pci_clr_err(void)
1661da177e4SLinus Torvalds {
1671da177e4SLinus Torvalds 	unsigned int nmi_ctl=0;
1681da177e4SLinus Torvalds 	unsigned int IRONGATE_jd;
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds again:
1711da177e4SLinus Torvalds 	IRONGATE_jd = IRONGATE0->stat_cmd;
1721da177e4SLinus Torvalds 	printk("Iron stat_cmd %x\n", IRONGATE_jd);
1731da177e4SLinus Torvalds 	IRONGATE0->stat_cmd = IRONGATE_jd; /* write again clears error bits */
1741da177e4SLinus Torvalds 	mb();
1751da177e4SLinus Torvalds 	IRONGATE_jd = IRONGATE0->stat_cmd;  /* re-read to force write */
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	IRONGATE_jd = *IronECC;
1781da177e4SLinus Torvalds 	printk("Iron ECC %x\n", IRONGATE_jd);
1791da177e4SLinus Torvalds 	*IronECC = IRONGATE_jd; /* write again clears error bits */
1801da177e4SLinus Torvalds 	mb();
1811da177e4SLinus Torvalds 	IRONGATE_jd = *IronECC;  /* re-read to force write */
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	/* Clear ALI NMI */
1841da177e4SLinus Torvalds         nmi_ctl = inb(0x61);
1851da177e4SLinus Torvalds         nmi_ctl |= 0x0c;
1861da177e4SLinus Torvalds         outb(nmi_ctl, 0x61);
1871da177e4SLinus Torvalds         nmi_ctl &= ~0x0c;
1881da177e4SLinus Torvalds         outb(nmi_ctl, 0x61);
1891da177e4SLinus Torvalds 
1901da177e4SLinus Torvalds 	IRONGATE_jd = *IronECC;
1911da177e4SLinus Torvalds 	if (IRONGATE_jd & 0x300) goto again;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	return 0;
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds #define IRONGATE_3GB 0xc0000000UL
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds /* On Albacore (aka UP1500) with 4Gb of RAM we have to reserve some
1991da177e4SLinus Torvalds    memory for PCI. At this point we just reserve memory above 3Gb. Most
2001da177e4SLinus Torvalds    of this memory will be freed after PCI setup is done. */
2011da177e4SLinus Torvalds static void __init
albacore_init_arch(void)2021da177e4SLinus Torvalds albacore_init_arch(void)
2031da177e4SLinus Torvalds {
2041da177e4SLinus Torvalds 	unsigned long memtop = max_low_pfn << PAGE_SHIFT;
2051da177e4SLinus Torvalds 	unsigned long pci_mem = (memtop + 0x1000000UL) & ~0xffffffUL;
2061da177e4SLinus Torvalds 	struct percpu_struct *cpu;
2071da177e4SLinus Torvalds 	int pal_rev, pal_var;
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset);
2101da177e4SLinus Torvalds 	pal_rev = cpu->pal_revision & 0xffff;
2111da177e4SLinus Torvalds 	pal_var = (cpu->pal_revision >> 16) & 0xff;
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 	/* Consoles earlier than A5.6-18 (OSF PALcode v1.62-2) set up
2141da177e4SLinus Torvalds 	   the CPU incorrectly (leave speculative stores enabled),
2151da177e4SLinus Torvalds 	   which causes memory corruption under certain conditions.
2161da177e4SLinus Torvalds 	   Issue a warning for such consoles. */
2171da177e4SLinus Torvalds 	if (alpha_using_srm &&
2181da177e4SLinus Torvalds 	    (pal_rev < 0x13e ||	(pal_rev == 0x13e && pal_var < 2)))
2191da177e4SLinus Torvalds 		printk(KERN_WARNING "WARNING! Upgrade to SRM A5.6-19 "
2201da177e4SLinus Torvalds 				    "or later\n");
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	if (pci_mem > IRONGATE_3GB)
2231da177e4SLinus Torvalds 		pci_mem = IRONGATE_3GB;
2241da177e4SLinus Torvalds 	IRONGATE0->pci_mem = pci_mem;
2251da177e4SLinus Torvalds 	alpha_mv.min_mem_address = pci_mem;
2261da177e4SLinus Torvalds 	if (memtop > pci_mem) {
2271da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_INITRD
2281da177e4SLinus Torvalds 		extern unsigned long initrd_start, initrd_end;
2291da177e4SLinus Torvalds 		extern void *move_initrd(unsigned long);
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 		/* Move the initrd out of the way. */
2321da177e4SLinus Torvalds 		if (initrd_end && __pa(initrd_end) > pci_mem) {
2331da177e4SLinus Torvalds 			unsigned long size;
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds 			size = initrd_end - initrd_start;
236*4421cca0SMike Rapoport 			memblock_free((void *)initrd_start, PAGE_ALIGN(size));
2371da177e4SLinus Torvalds 			if (!move_initrd(pci_mem))
2381da177e4SLinus Torvalds 				printk("irongate_init_arch: initrd too big "
2391da177e4SLinus Torvalds 				       "(%ldK)\ndisabling initrd\n",
2401da177e4SLinus Torvalds 				       size / 1024);
2411da177e4SLinus Torvalds 		}
2421da177e4SLinus Torvalds #endif
2436471f52aSMike Rapoport 		memblock_reserve(pci_mem, memtop - pci_mem);
2441da177e4SLinus Torvalds 		printk("irongate_init_arch: temporarily reserving "
2451da177e4SLinus Torvalds 			"region %08lx-%08lx for PCI\n", pci_mem, memtop - 1);
2461da177e4SLinus Torvalds 	}
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds static void __init
irongate_setup_agp(void)2501da177e4SLinus Torvalds irongate_setup_agp(void)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds 	/* Disable the GART window. AGPGART doesn't work due to yet
2531da177e4SLinus Torvalds 	   unresolved memory coherency issues... */
2541da177e4SLinus Torvalds 	IRONGATE0->agpva = IRONGATE0->agpva & ~0xf;
2551da177e4SLinus Torvalds 	alpha_agpgart_size = 0;
2561da177e4SLinus Torvalds }
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds void __init
irongate_init_arch(void)2591da177e4SLinus Torvalds irongate_init_arch(void)
2601da177e4SLinus Torvalds {
2611da177e4SLinus Torvalds 	struct pci_controller *hose;
2621da177e4SLinus Torvalds 	int amd761 = (IRONGATE0->dev_vendor >> 16) > 0x7006;	/* Albacore? */
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 	IronECC = amd761 ? &IRONGATE0->bacsr54_eccms761 : &IRONGATE0->dramms;
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	irongate_pci_clr_err();
2671da177e4SLinus Torvalds 
2681da177e4SLinus Torvalds 	if (amd761)
2691da177e4SLinus Torvalds 		albacore_init_arch();
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	irongate_setup_agp();
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	/*
2741da177e4SLinus Torvalds 	 * Create our single hose.
2751da177e4SLinus Torvalds 	 */
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	pci_isa_hose = hose = alloc_pci_controller();
2781da177e4SLinus Torvalds 	hose->io_space = &ioport_resource;
2791da177e4SLinus Torvalds 	hose->mem_space = &iomem_resource;
2801da177e4SLinus Torvalds 	hose->index = 0;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	/* This is for userland consumption.  For some reason, the 40-bit
2831da177e4SLinus Torvalds 	   PIO bias that we use in the kernel through KSEG didn't work for
2841da177e4SLinus Torvalds 	   the page table based user mappings.  So make sure we get the
2851da177e4SLinus Torvalds 	   43-bit PIO bias.  */
2861da177e4SLinus Torvalds 	hose->sparse_mem_base = 0;
2871da177e4SLinus Torvalds 	hose->sparse_io_base = 0;
2881da177e4SLinus Torvalds 	hose->dense_mem_base
2891da177e4SLinus Torvalds 	  = (IRONGATE_MEM & 0xffffffffffUL) | 0x80000000000UL;
2901da177e4SLinus Torvalds 	hose->dense_io_base
2911da177e4SLinus Torvalds 	  = (IRONGATE_IO & 0xffffffffffUL) | 0x80000000000UL;
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	hose->sg_isa = hose->sg_pci = NULL;
2941da177e4SLinus Torvalds 	__direct_map_base = 0;
2951da177e4SLinus Torvalds 	__direct_map_size = 0xffffffff;
2961da177e4SLinus Torvalds }
2971da177e4SLinus Torvalds 
2981da177e4SLinus Torvalds /*
2991da177e4SLinus Torvalds  * IO map and AGP support
3001da177e4SLinus Torvalds  */
3011da177e4SLinus Torvalds #include <linux/vmalloc.h>
3021da177e4SLinus Torvalds #include <linux/agp_backend.h>
3031da177e4SLinus Torvalds #include <linux/agpgart.h>
30400cd1176SPaul Gortmaker #include <linux/export.h>
3051da177e4SLinus Torvalds 
3061da177e4SLinus Torvalds #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
3071da177e4SLinus Torvalds #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
3101da177e4SLinus Torvalds #define GET_GATT(addr) (gatt_pages[GET_PAGE_DIR_IDX(addr)])
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds void __iomem *
irongate_ioremap(unsigned long addr,unsigned long size)3131da177e4SLinus Torvalds irongate_ioremap(unsigned long addr, unsigned long size)
3141da177e4SLinus Torvalds {
3151da177e4SLinus Torvalds 	struct vm_struct *area;
3161da177e4SLinus Torvalds 	unsigned long vaddr;
3171da177e4SLinus Torvalds 	unsigned long baddr, last;
3181da177e4SLinus Torvalds 	u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
3191da177e4SLinus Torvalds 	unsigned long gart_bus_addr;
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 	if (!alpha_agpgart_size)
3221da177e4SLinus Torvalds 		return (void __iomem *)(addr + IRONGATE_MEM);
3231da177e4SLinus Torvalds 
3241da177e4SLinus Torvalds 	gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
3251da177e4SLinus Torvalds 			PCI_BASE_ADDRESS_MEM_MASK;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	/*
3281da177e4SLinus Torvalds 	 * Check for within the AGP aperture...
3291da177e4SLinus Torvalds 	 */
3301da177e4SLinus Torvalds 	do {
3311da177e4SLinus Torvalds 		/*
3321da177e4SLinus Torvalds 		 * Check the AGP area
3331da177e4SLinus Torvalds 		 */
3341da177e4SLinus Torvalds 		if (addr >= gart_bus_addr && addr + size - 1 <
3351da177e4SLinus Torvalds 		    gart_bus_addr + alpha_agpgart_size)
3361da177e4SLinus Torvalds 			break;
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 		/*
3391da177e4SLinus Torvalds 		 * Not found - assume legacy ioremap
3401da177e4SLinus Torvalds 		 */
3411da177e4SLinus Torvalds 		return (void __iomem *)(addr + IRONGATE_MEM);
3421da177e4SLinus Torvalds 	} while(0);
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 	mmio_regs = (u32 *)(((unsigned long)IRONGATE0->bar1 &
3451da177e4SLinus Torvalds 			PCI_BASE_ADDRESS_MEM_MASK) + IRONGATE_MEM);
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	gatt_pages = (u32 *)(phys_to_virt(mmio_regs[1])); /* FIXME */
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	/*
3501da177e4SLinus Torvalds 	 * Adjust the limits (mappings must be page aligned)
3511da177e4SLinus Torvalds 	 */
3521da177e4SLinus Torvalds 	if (addr & ~PAGE_MASK) {
3531da177e4SLinus Torvalds 		printk("AGP ioremap failed... addr not page aligned (0x%lx)\n",
3541da177e4SLinus Torvalds 		       addr);
3551da177e4SLinus Torvalds 		return (void __iomem *)(addr + IRONGATE_MEM);
3561da177e4SLinus Torvalds 	}
3571da177e4SLinus Torvalds 	last = addr + size - 1;
3581da177e4SLinus Torvalds 	size = PAGE_ALIGN(last) - addr;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds #if 0
3611da177e4SLinus Torvalds 	printk("irongate_ioremap(0x%lx, 0x%lx)\n", addr, size);
3621da177e4SLinus Torvalds 	printk("irongate_ioremap:  gart_bus_addr  0x%lx\n", gart_bus_addr);
3631da177e4SLinus Torvalds 	printk("irongate_ioremap:  gart_aper_size 0x%lx\n", gart_aper_size);
3641da177e4SLinus Torvalds 	printk("irongate_ioremap:  mmio_regs      %p\n", mmio_regs);
3651da177e4SLinus Torvalds 	printk("irongate_ioremap:  gatt_pages     %p\n", gatt_pages);
3661da177e4SLinus Torvalds 
3671da177e4SLinus Torvalds 	for(baddr = addr; baddr <= last; baddr += PAGE_SIZE)
3681da177e4SLinus Torvalds 	{
3691da177e4SLinus Torvalds 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
3701da177e4SLinus Torvalds 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
3711da177e4SLinus Torvalds 		printk("irongate_ioremap:  cur_gatt %p pte 0x%x\n",
3721da177e4SLinus Torvalds 		       cur_gatt, pte);
3731da177e4SLinus Torvalds 	}
3741da177e4SLinus Torvalds #endif
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	/*
3771da177e4SLinus Torvalds 	 * Map it
3781da177e4SLinus Torvalds 	 */
3791da177e4SLinus Torvalds 	area = get_vm_area(size, VM_IOREMAP);
3801da177e4SLinus Torvalds 	if (!area) return NULL;
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	for(baddr = addr, vaddr = (unsigned long)area->addr;
3831da177e4SLinus Torvalds 	    baddr <= last;
3841da177e4SLinus Torvalds 	    baddr += PAGE_SIZE, vaddr += PAGE_SIZE)
3851da177e4SLinus Torvalds 	{
3861da177e4SLinus Torvalds 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
3871da177e4SLinus Torvalds 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 		if (__alpha_remap_area_pages(vaddr,
3901da177e4SLinus Torvalds 					     pte, PAGE_SIZE, 0)) {
3911da177e4SLinus Torvalds 			printk("AGP ioremap: FAILED to map...\n");
3921da177e4SLinus Torvalds 			vfree(area->addr);
3931da177e4SLinus Torvalds 			return NULL;
3941da177e4SLinus Torvalds 		}
3951da177e4SLinus Torvalds 	}
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 	flush_tlb_all();
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
4001da177e4SLinus Torvalds #if 0
4011da177e4SLinus Torvalds 	printk("irongate_ioremap(0x%lx, 0x%lx) returning 0x%lx\n",
4021da177e4SLinus Torvalds 	       addr, size, vaddr);
4031da177e4SLinus Torvalds #endif
4041da177e4SLinus Torvalds 	return (void __iomem *)vaddr;
4051da177e4SLinus Torvalds }
406cff52dafSAl Viro EXPORT_SYMBOL(irongate_ioremap);
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds void
irongate_iounmap(volatile void __iomem * xaddr)4091da177e4SLinus Torvalds irongate_iounmap(volatile void __iomem *xaddr)
4101da177e4SLinus Torvalds {
4111da177e4SLinus Torvalds 	unsigned long addr = (unsigned long) xaddr;
4121da177e4SLinus Torvalds 	if (((long)addr >> 41) == -2)
4131da177e4SLinus Torvalds 		return;	/* kseg map, nothing to do */
4141da177e4SLinus Torvalds 	if (addr)
4151da177e4SLinus Torvalds 		return vfree((void *)(PAGE_MASK & addr));
4161da177e4SLinus Torvalds }
417cff52dafSAl Viro EXPORT_SYMBOL(irongate_iounmap);
418