| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  *	linux/arch/alpha/kernel/core_irongate.c | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com). | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  *	Copyright (C) 1999 Alpha Processor, Inc., | 
					
						
							|  |  |  |  |  *		(David Daniel, Stig Telfer, Soohoon Lee) | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Code common to all IRONGATE core logic chips. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define __EXTERN_INLINE inline
 | 
					
						
							|  |  |  |  | #include <asm/io.h>
 | 
					
						
							|  |  |  |  | #include <asm/core_irongate.h>
 | 
					
						
							|  |  |  |  | #undef __EXTERN_INLINE
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  |  | #include <linux/initrd.h>
 | 
					
						
							|  |  |  |  | #include <linux/bootmem.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <asm/ptrace.h>
 | 
					
						
							|  |  |  |  | #include <asm/pci.h>
 | 
					
						
							|  |  |  |  | #include <asm/cacheflush.h>
 | 
					
						
							|  |  |  |  | #include <asm/tlbflush.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "proto.h"
 | 
					
						
							|  |  |  |  | #include "pci_impl.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * BIOS32-style PCI interface: | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define DEBUG_CONFIG 0
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #if DEBUG_CONFIG
 | 
					
						
							|  |  |  |  | # define DBG_CFG(args)	printk args
 | 
					
						
							|  |  |  |  | #else
 | 
					
						
							|  |  |  |  | # define DBG_CFG(args)
 | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | igcsr32 *IronECC; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * Given a bus, device, and function number, compute resulting | 
					
						
							|  |  |  |  |  * configuration space address accordingly.  It is therefore not safe | 
					
						
							|  |  |  |  |  * to have concurrent invocations to configuration space access | 
					
						
							|  |  |  |  |  * routines, but there really shouldn't be any need for this. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  *	addr[31:24]		reserved | 
					
						
							|  |  |  |  |  *	addr[23:16]		bus number (8 bits = 128 possible buses) | 
					
						
							|  |  |  |  |  *	addr[15:11]		Device number (5 bits) | 
					
						
							|  |  |  |  |  *	addr[10: 8]		function number | 
					
						
							|  |  |  |  |  *	addr[ 7: 2]		register number | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * For IRONGATE: | 
					
						
							|  |  |  |  |  *    if (bus = addr[23:16]) == 0 | 
					
						
							|  |  |  |  |  *    then | 
					
						
							|  |  |  |  |  *	  type 0 config cycle: | 
					
						
							|  |  |  |  |  *	      addr_on_pci[31:11] = id selection for device = addr[15:11] | 
					
						
							|  |  |  |  |  *	      addr_on_pci[10: 2] = addr[10: 2] ??? | 
					
						
							|  |  |  |  |  *	      addr_on_pci[ 1: 0] = 00 | 
					
						
							|  |  |  |  |  *    else | 
					
						
							|  |  |  |  |  *	  type 1 config cycle (pass on with no decoding): | 
					
						
							|  |  |  |  |  *	      addr_on_pci[31:24] = 0 | 
					
						
							|  |  |  |  |  *	      addr_on_pci[23: 2] = addr[23: 2] | 
					
						
							|  |  |  |  |  *	      addr_on_pci[ 1: 0] = 01 | 
					
						
							|  |  |  |  |  *    fi | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Notes: | 
					
						
							|  |  |  |  |  *	The function number selects which function of a multi-function device | 
					
						
							|  |  |  |  |  *	(e.g., SCSI and Ethernet). | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  *	The register selects a DWORD (32 bit) register offset.	Hence it | 
					
						
							|  |  |  |  |  *	doesn't get shifted by 2 bits as we want to "drop" the bottom two | 
					
						
							|  |  |  |  |  *	bits. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int | 
					
						
							|  |  |  |  | mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where, | 
					
						
							|  |  |  |  | 	     unsigned long *pci_addr, unsigned char *type1) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	unsigned long addr; | 
					
						
							|  |  |  |  | 	u8 bus = pbus->number; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " | 
					
						
							|  |  |  |  | 		 "pci_addr=0x%p, type1=0x%p)\n", | 
					
						
							|  |  |  |  | 		 bus, device_fn, where, pci_addr, type1)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	*type1 = (bus != 0); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	addr = (bus << 16) | (device_fn << 8) | where; | 
					
						
							|  |  |  |  | 	addr |= IRONGATE_CONF; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	*pci_addr = addr; | 
					
						
							|  |  |  |  | 	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); | 
					
						
							|  |  |  |  | 	return 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int | 
					
						
							|  |  |  |  | irongate_read_config(struct pci_bus *bus, unsigned int devfn, int where, | 
					
						
							|  |  |  |  | 		     int size, u32 *value) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	unsigned long addr; | 
					
						
							|  |  |  |  | 	unsigned char type1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if (mk_conf_addr(bus, devfn, where, &addr, &type1)) | 
					
						
							|  |  |  |  | 		return PCIBIOS_DEVICE_NOT_FOUND; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch (size) { | 
					
						
							|  |  |  |  | 	case 1: | 
					
						
							|  |  |  |  | 		*value = __kernel_ldbu(*(vucp)addr); | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	case 2: | 
					
						
							|  |  |  |  | 		*value = __kernel_ldwu(*(vusp)addr); | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	case 4: | 
					
						
							|  |  |  |  | 		*value = *(vuip)addr; | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return PCIBIOS_SUCCESSFUL; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static int | 
					
						
							|  |  |  |  | irongate_write_config(struct pci_bus *bus, unsigned int devfn, int where, | 
					
						
							|  |  |  |  | 		      int size, u32 value) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	unsigned long addr; | 
					
						
							|  |  |  |  | 	unsigned char type1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if (mk_conf_addr(bus, devfn, where, &addr, &type1)) | 
					
						
							|  |  |  |  | 		return PCIBIOS_DEVICE_NOT_FOUND; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch (size) { | 
					
						
							|  |  |  |  | 	case 1: | 
					
						
							|  |  |  |  | 		__kernel_stb(value, *(vucp)addr); | 
					
						
							|  |  |  |  | 		mb(); | 
					
						
							|  |  |  |  | 		__kernel_ldbu(*(vucp)addr); | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	case 2: | 
					
						
							|  |  |  |  | 		__kernel_stw(value, *(vusp)addr); | 
					
						
							|  |  |  |  | 		mb(); | 
					
						
							|  |  |  |  | 		__kernel_ldwu(*(vusp)addr); | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	case 4: | 
					
						
							|  |  |  |  | 		*(vuip)addr = value; | 
					
						
							|  |  |  |  | 		mb(); | 
					
						
							|  |  |  |  | 		*(vuip)addr; | 
					
						
							|  |  |  |  | 		break; | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return PCIBIOS_SUCCESSFUL; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | struct pci_ops irongate_pci_ops = | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	.read =		irongate_read_config, | 
					
						
							|  |  |  |  | 	.write =	irongate_write_config, | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  |  | 
					
						
							|  |  |  |  | int | 
					
						
							|  |  |  |  | irongate_pci_clr_err(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	unsigned int nmi_ctl=0; | 
					
						
							|  |  |  |  | 	unsigned int IRONGATE_jd; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | again: | 
					
						
							|  |  |  |  | 	IRONGATE_jd = IRONGATE0->stat_cmd; | 
					
						
							|  |  |  |  | 	printk("Iron stat_cmd %x\n", IRONGATE_jd); | 
					
						
							|  |  |  |  | 	IRONGATE0->stat_cmd = IRONGATE_jd; /* write again clears error bits */ | 
					
						
							|  |  |  |  | 	mb(); | 
					
						
							|  |  |  |  | 	IRONGATE_jd = IRONGATE0->stat_cmd;  /* re-read to force write */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	IRONGATE_jd = *IronECC; | 
					
						
							|  |  |  |  | 	printk("Iron ECC %x\n", IRONGATE_jd); | 
					
						
							|  |  |  |  | 	*IronECC = IRONGATE_jd; /* write again clears error bits */ | 
					
						
							|  |  |  |  | 	mb(); | 
					
						
							|  |  |  |  | 	IRONGATE_jd = *IronECC;  /* re-read to force write */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/* Clear ALI NMI */ | 
					
						
							|  |  |  |  |         nmi_ctl = inb(0x61); | 
					
						
							|  |  |  |  |         nmi_ctl |= 0x0c; | 
					
						
							|  |  |  |  |         outb(nmi_ctl, 0x61); | 
					
						
							|  |  |  |  |         nmi_ctl &= ~0x0c; | 
					
						
							|  |  |  |  |         outb(nmi_ctl, 0x61); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	IRONGATE_jd = *IronECC; | 
					
						
							|  |  |  |  | 	if (IRONGATE_jd & 0x300) goto again; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define IRONGATE_3GB 0xc0000000UL
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* On Albacore (aka UP1500) with 4Gb of RAM we have to reserve some
 | 
					
						
							|  |  |  |  |    memory for PCI. At this point we just reserve memory above 3Gb. Most | 
					
						
							|  |  |  |  |    of this memory will be freed after PCI setup is done. */ | 
					
						
							|  |  |  |  | static void __init | 
					
						
							|  |  |  |  | albacore_init_arch(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	unsigned long memtop = max_low_pfn << PAGE_SHIFT; | 
					
						
							|  |  |  |  | 	unsigned long pci_mem = (memtop + 0x1000000UL) & ~0xffffffUL; | 
					
						
							|  |  |  |  | 	struct percpu_struct *cpu; | 
					
						
							|  |  |  |  | 	int pal_rev, pal_var; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset); | 
					
						
							|  |  |  |  | 	pal_rev = cpu->pal_revision & 0xffff; | 
					
						
							|  |  |  |  | 	pal_var = (cpu->pal_revision >> 16) & 0xff; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/* Consoles earlier than A5.6-18 (OSF PALcode v1.62-2) set up
 | 
					
						
							|  |  |  |  | 	   the CPU incorrectly (leave speculative stores enabled), | 
					
						
							|  |  |  |  | 	   which causes memory corruption under certain conditions. | 
					
						
							|  |  |  |  | 	   Issue a warning for such consoles. */ | 
					
						
							|  |  |  |  | 	if (alpha_using_srm && | 
					
						
							|  |  |  |  | 	    (pal_rev < 0x13e ||	(pal_rev == 0x13e && pal_var < 2))) | 
					
						
							|  |  |  |  | 		printk(KERN_WARNING "WARNING! Upgrade to SRM A5.6-19 " | 
					
						
							|  |  |  |  | 				    "or later\n"); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if (pci_mem > IRONGATE_3GB) | 
					
						
							|  |  |  |  | 		pci_mem = IRONGATE_3GB; | 
					
						
							|  |  |  |  | 	IRONGATE0->pci_mem = pci_mem; | 
					
						
							|  |  |  |  | 	alpha_mv.min_mem_address = pci_mem; | 
					
						
							|  |  |  |  | 	if (memtop > pci_mem) { | 
					
						
							|  |  |  |  | #ifdef CONFIG_BLK_DEV_INITRD
 | 
					
						
							|  |  |  |  | 		extern unsigned long initrd_start, initrd_end; | 
					
						
							|  |  |  |  | 		extern void *move_initrd(unsigned long); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		/* Move the initrd out of the way. */ | 
					
						
							|  |  |  |  | 		if (initrd_end && __pa(initrd_end) > pci_mem) { | 
					
						
							|  |  |  |  | 			unsigned long size; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			size = initrd_end - initrd_start; | 
					
						
							|  |  |  |  | 			free_bootmem_node(NODE_DATA(0), __pa(initrd_start), | 
					
						
							|  |  |  |  | 					  PAGE_ALIGN(size)); | 
					
						
							|  |  |  |  | 			if (!move_initrd(pci_mem)) | 
					
						
							|  |  |  |  | 				printk("irongate_init_arch: initrd too big " | 
					
						
							|  |  |  |  | 				       "(%ldK)\ndisabling initrd\n", | 
					
						
							|  |  |  |  | 				       size / 1024); | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2008-02-07 00:15:17 -08:00
										 |  |  |  | 		reserve_bootmem_node(NODE_DATA(0), pci_mem, memtop - | 
					
						
							|  |  |  |  | 				pci_mem, BOOTMEM_DEFAULT); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  | 		printk("irongate_init_arch: temporarily reserving " | 
					
						
							|  |  |  |  | 			"region %08lx-%08lx for PCI\n", pci_mem, memtop - 1); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void __init | 
					
						
							|  |  |  |  | irongate_setup_agp(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	/* Disable the GART window. AGPGART doesn't work due to yet
 | 
					
						
							|  |  |  |  | 	   unresolved memory coherency issues... */ | 
					
						
							|  |  |  |  | 	IRONGATE0->agpva = IRONGATE0->agpva & ~0xf; | 
					
						
							|  |  |  |  | 	alpha_agpgart_size = 0; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | void __init | 
					
						
							|  |  |  |  | irongate_init_arch(void) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	struct pci_controller *hose; | 
					
						
							|  |  |  |  | 	int amd761 = (IRONGATE0->dev_vendor >> 16) > 0x7006;	/* Albacore? */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	IronECC = amd761 ? &IRONGATE0->bacsr54_eccms761 : &IRONGATE0->dramms; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	irongate_pci_clr_err(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if (amd761) | 
					
						
							|  |  |  |  | 		albacore_init_arch(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	irongate_setup_agp(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/*
 | 
					
						
							|  |  |  |  | 	 * Create our single hose. | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	pci_isa_hose = hose = alloc_pci_controller(); | 
					
						
							|  |  |  |  | 	hose->io_space = &ioport_resource; | 
					
						
							|  |  |  |  | 	hose->mem_space = &iomem_resource; | 
					
						
							|  |  |  |  | 	hose->index = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/* This is for userland consumption.  For some reason, the 40-bit
 | 
					
						
							|  |  |  |  | 	   PIO bias that we use in the kernel through KSEG didn't work for | 
					
						
							|  |  |  |  | 	   the page table based user mappings.  So make sure we get the | 
					
						
							|  |  |  |  | 	   43-bit PIO bias.  */ | 
					
						
							|  |  |  |  | 	hose->sparse_mem_base = 0; | 
					
						
							|  |  |  |  | 	hose->sparse_io_base = 0; | 
					
						
							|  |  |  |  | 	hose->dense_mem_base | 
					
						
							|  |  |  |  | 	  = (IRONGATE_MEM & 0xffffffffffUL) | 0x80000000000UL; | 
					
						
							|  |  |  |  | 	hose->dense_io_base | 
					
						
							|  |  |  |  | 	  = (IRONGATE_IO & 0xffffffffffUL) | 0x80000000000UL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	hose->sg_isa = hose->sg_pci = NULL; | 
					
						
							|  |  |  |  | 	__direct_map_base = 0; | 
					
						
							|  |  |  |  | 	__direct_map_size = 0xffffffff; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * IO map and AGP support | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | #include <linux/vmalloc.h>
 | 
					
						
							|  |  |  |  | #include <linux/agp_backend.h>
 | 
					
						
							|  |  |  |  | #include <linux/agpgart.h>
 | 
					
						
							|  |  |  |  | #include <asm/pgalloc.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 | 
					
						
							|  |  |  |  | #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) 
 | 
					
						
							|  |  |  |  | #define GET_GATT(addr) (gatt_pages[GET_PAGE_DIR_IDX(addr)])
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | void __iomem * | 
					
						
							|  |  |  |  | irongate_ioremap(unsigned long addr, unsigned long size) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	struct vm_struct *area; | 
					
						
							|  |  |  |  | 	unsigned long vaddr; | 
					
						
							|  |  |  |  | 	unsigned long baddr, last; | 
					
						
							|  |  |  |  | 	u32 *mmio_regs, *gatt_pages, *cur_gatt, pte; | 
					
						
							|  |  |  |  | 	unsigned long gart_bus_addr; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if (!alpha_agpgart_size) | 
					
						
							|  |  |  |  | 		return (void __iomem *)(addr + IRONGATE_MEM); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	gart_bus_addr = (unsigned long)IRONGATE0->bar0 & | 
					
						
							|  |  |  |  | 			PCI_BASE_ADDRESS_MEM_MASK;  | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/* 
 | 
					
						
							|  |  |  |  | 	 * Check for within the AGP aperture... | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 	do { | 
					
						
							|  |  |  |  | 		/*
 | 
					
						
							|  |  |  |  | 		 * Check the AGP area | 
					
						
							|  |  |  |  | 		 */ | 
					
						
							|  |  |  |  | 		if (addr >= gart_bus_addr && addr + size - 1 <  | 
					
						
							|  |  |  |  | 		    gart_bus_addr + alpha_agpgart_size) | 
					
						
							|  |  |  |  | 			break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		/*
 | 
					
						
							|  |  |  |  | 		 * Not found - assume legacy ioremap | 
					
						
							|  |  |  |  | 		 */ | 
					
						
							|  |  |  |  | 		return (void __iomem *)(addr + IRONGATE_MEM); | 
					
						
							|  |  |  |  | 	} while(0); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	mmio_regs = (u32 *)(((unsigned long)IRONGATE0->bar1 & | 
					
						
							|  |  |  |  | 			PCI_BASE_ADDRESS_MEM_MASK) + IRONGATE_MEM); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	gatt_pages = (u32 *)(phys_to_virt(mmio_regs[1])); /* FIXME */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/*
 | 
					
						
							|  |  |  |  | 	 * Adjust the limits (mappings must be page aligned) | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 	if (addr & ~PAGE_MASK) { | 
					
						
							|  |  |  |  | 		printk("AGP ioremap failed... addr not page aligned (0x%lx)\n", | 
					
						
							|  |  |  |  | 		       addr); | 
					
						
							|  |  |  |  | 		return (void __iomem *)(addr + IRONGATE_MEM); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	last = addr + size - 1; | 
					
						
							|  |  |  |  | 	size = PAGE_ALIGN(last) - addr; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #if 0
 | 
					
						
							|  |  |  |  | 	printk("irongate_ioremap(0x%lx, 0x%lx)\n", addr, size); | 
					
						
							|  |  |  |  | 	printk("irongate_ioremap:  gart_bus_addr  0x%lx\n", gart_bus_addr); | 
					
						
							|  |  |  |  | 	printk("irongate_ioremap:  gart_aper_size 0x%lx\n", gart_aper_size); | 
					
						
							|  |  |  |  | 	printk("irongate_ioremap:  mmio_regs      %p\n", mmio_regs); | 
					
						
							|  |  |  |  | 	printk("irongate_ioremap:  gatt_pages     %p\n", gatt_pages); | 
					
						
							|  |  |  |  | 	 | 
					
						
							|  |  |  |  | 	for(baddr = addr; baddr <= last; baddr += PAGE_SIZE) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1); | 
					
						
							|  |  |  |  | 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1; | 
					
						
							|  |  |  |  | 		printk("irongate_ioremap:  cur_gatt %p pte 0x%x\n", | 
					
						
							|  |  |  |  | 		       cur_gatt, pte); | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	/*
 | 
					
						
							|  |  |  |  | 	 * Map it | 
					
						
							|  |  |  |  | 	 */ | 
					
						
							|  |  |  |  | 	area = get_vm_area(size, VM_IOREMAP); | 
					
						
							|  |  |  |  | 	if (!area) return NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for(baddr = addr, vaddr = (unsigned long)area->addr;  | 
					
						
							|  |  |  |  | 	    baddr <= last;  | 
					
						
							|  |  |  |  | 	    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) | 
					
						
							|  |  |  |  | 	{ | 
					
						
							|  |  |  |  | 		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1); | 
					
						
							|  |  |  |  | 		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if (__alpha_remap_area_pages(vaddr, | 
					
						
							|  |  |  |  | 					     pte, PAGE_SIZE, 0)) { | 
					
						
							|  |  |  |  | 			printk("AGP ioremap: FAILED to map...\n"); | 
					
						
							|  |  |  |  | 			vfree(area->addr); | 
					
						
							|  |  |  |  | 			return NULL; | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	flush_tlb_all(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK); | 
					
						
							|  |  |  |  | #if 0
 | 
					
						
							|  |  |  |  | 	printk("irongate_ioremap(0x%lx, 0x%lx) returning 0x%lx\n", | 
					
						
							|  |  |  |  | 	       addr, size, vaddr); | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  | 	return (void __iomem *)vaddr; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-10-11 17:40:22 +01:00
										 |  |  |  | EXPORT_SYMBOL(irongate_ioremap); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | void | 
					
						
							|  |  |  |  | irongate_iounmap(volatile void __iomem *xaddr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	unsigned long addr = (unsigned long) xaddr; | 
					
						
							|  |  |  |  | 	if (((long)addr >> 41) == -2) | 
					
						
							|  |  |  |  | 		return;	/* kseg map, nothing to do */ | 
					
						
							|  |  |  |  | 	if (addr) | 
					
						
							|  |  |  |  | 		return vfree((void *)(PAGE_MASK & addr));  | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2006-10-11 17:40:22 +01:00
										 |  |  |  | EXPORT_SYMBOL(irongate_iounmap); |