onECC;  /* 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;

		/* Move the initrd out of the way. */
		if (initrd_end && __pa(initrd_end) > pci_mem) {
			unsigned long size;

			size = initrd_end - initrd_start;
			memblock_free((void *)initrd_start, PAGE_ALIGN(size));
			if (!move_initrd(pci_mem))
				printk("irongate_init_arch: initrd too big "
				       "(%ldK)\ndisabling initrd\n",
				       size / 1024);
		}
#endif
		memblock_reserve(pci_mem, memtop - pci_mem);
		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 <linux/export.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;
}
EXPORT_SYMBOL(irongate_ioremap);

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)); 
}
EXPORT_SYMBOL(irongate_iounmap);
