Commit 2192cb52 authored by Ivan Kokshaysky's avatar Ivan Kokshaysky Committed by Richard Henderson

[PATCH] nautilus update

- make irongate_ioremap() use generic __alpha_remap_area_pages();
- remove huge debugging printk;
- AGP remapping hardware disabled for now. Any attempt to use it
  would result in corrupted memory;
- albacore (UP1500) support:
  - handle differences between AMD-761 (UP1500) and AMD-751 (UP1000/1100)
    chipsets, namely ECC mode/status and pci_mem registers;
  - customized nautilus_init_pci() to minimize amount of system memory
    consumed by PCI MMIO for 4Gb configuration.

Ivan.
parent 785520ce
......@@ -27,13 +27,11 @@
#include <asm/core_irongate.h>
#undef __EXTERN_INLINE
#include <linux/bootmem.h>
#include "proto.h"
#include "pci_impl.h"
#undef DEBUG_IRONGATE /* define to enable verbose Irongate debug */
#define IRONGATE_DEFAULT_AGP_APER_SIZE (256*1024*1024) /* 256MB */
/*
* BIOS32-style PCI interface:
*/
......@@ -46,6 +44,7 @@
# define DBG_CFG(args)
#endif
igcsr32 *IronECC;
/*
* Given a bus, device, and function number, compute resulting
......@@ -165,143 +164,6 @@ struct pci_ops irongate_pci_ops =
.write = irongate_write_config,
};
#ifdef DEBUG_IRONGATE
static void
irongate_register_dump(const char *function_name)
{
printk("%s: Irongate registers:\n"
"\tFunction 0:\n"
"\tdev_vendor\t0x%08x\n"
"\tstat_cmd\t0x%08x\n"
"\tclass\t\t0x%08x\n"
"\tlatency\t\t0x%08x\n"
"\tbar0\t\t0x%08x\n"
"\tbar1\t\t0x%08x\n"
"\tbar2\t\t0x%08x\n"
"\trsrvd0[0]\t0x%08x\n"
"\trsrvd0[1]\t0x%08x\n"
"\trsrvd0[2]\t0x%08x\n"
"\trsrvd0[3]\t0x%08x\n"
"\trsrvd0[4]\t0x%08x\n"
"\trsrvd0[5]\t0x%08x\n"
"\tcapptr\t\t0x%08x\n"
"\trsrvd1[0]\t0x%08x\n"
"\trsrvd1[1]\t0x%08x\n"
"\tbacsr10\t\t0x%08x\n"
"\tbacsr32\t\t0x%08x\n"
"\tbacsr54\t\t0x%08x\n"
"\trsrvd2[0]\t0x%08x\n"
"\tdrammap\t\t0x%08x\n"
"\tdramtm\t\t0x%08x\n"
"\tdramms\t\t0x%08x\n"
"\trsrvd3[0]\t0x%08x\n"
"\tbiu0\t\t0x%08x\n"
"\tbiusip\t\t0x%08x\n"
"\trsrvd4[0]\t0x%08x\n"
"\trsrvd4[1]\t0x%08x\n"
"\tmro\t\t0x%08x\n"
"\trsrvd5[0]\t0x%08x\n"
"\trsrvd5[1]\t0x%08x\n"
"\trsrvd5[2]\t0x%08x\n"
"\twhami\t\t0x%08x\n"
"\tpciarb\t\t0x%08x\n"
"\tpcicfg\t\t0x%08x\n"
"\trsrvd6[0]\t0x%08x\n"
"\trsrvd6[1]\t0x%08x\n"
"\trsrvd6[2]\t0x%08x\n"
"\trsrvd6[3]\t0x%08x\n"
"\trsrvd6[4]\t0x%08x\n"
"\tagpcap\t\t0x%08x\n"
"\tagpstat\t\t0x%08x\n"
"\tagpcmd\t\t0x%08x\n"
"\tagpva\t\t0x%08x\n"
"\tagpmode\t\t0x%08x\n"
"\n\tFunction 1:\n"
"\tdev_vendor:\t0x%08x\n"
"\tcmd_status:\t0x%08x\n"
"\trevid_etc :\t0x%08x\n"
"\thtype_etc :\t0x%08x\n"
"\trsrvd0[0] :\t0x%08x\n"
"\trsrvd0[1] :\t0x%08x\n"
"\tbus_nmbers:\t0x%08x\n"
"\tio_baselim:\t0x%08x\n"
"\tmem_bselim:\t0x%08x\n"
"\tpf_baselib:\t0x%08x\n"
"\trsrvd1[0] :\t0x%08x\n"
"\trsrvd1[1] :\t0x%08x\n"
"\tio_baselim:\t0x%08x\n"
"\trsrvd2[0] :\t0x%08x\n"
"\trsrvd2[1] :\t0x%08x\n"
"\tinterrupt :\t0x%08x\n",
function_name,
IRONGATE0->dev_vendor,
IRONGATE0->stat_cmd,
IRONGATE0->class,
IRONGATE0->latency,
IRONGATE0->bar0,
IRONGATE0->bar1,
IRONGATE0->bar2,
IRONGATE0->rsrvd0[0],
IRONGATE0->rsrvd0[1],
IRONGATE0->rsrvd0[2],
IRONGATE0->rsrvd0[3],
IRONGATE0->rsrvd0[4],
IRONGATE0->rsrvd0[5],
IRONGATE0->capptr,
IRONGATE0->rsrvd1[0],
IRONGATE0->rsrvd1[1],
IRONGATE0->bacsr10,
IRONGATE0->bacsr32,
IRONGATE0->bacsr54,
IRONGATE0->rsrvd2[0],
IRONGATE0->drammap,
IRONGATE0->dramtm,
IRONGATE0->dramms,
IRONGATE0->rsrvd3[0],
IRONGATE0->biu0,
IRONGATE0->biusip,
IRONGATE0->rsrvd4[0],
IRONGATE0->rsrvd4[1],
IRONGATE0->mro,
IRONGATE0->rsrvd5[0],
IRONGATE0->rsrvd5[1],
IRONGATE0->rsrvd5[2],
IRONGATE0->whami,
IRONGATE0->pciarb,
IRONGATE0->pcicfg,
IRONGATE0->rsrvd6[0],
IRONGATE0->rsrvd6[1],
IRONGATE0->rsrvd6[2],
IRONGATE0->rsrvd6[3],
IRONGATE0->rsrvd6[4],
IRONGATE0->agpcap,
IRONGATE0->agpstat,
IRONGATE0->agpcmd,
IRONGATE0->agpva,
IRONGATE0->agpmode,
IRONGATE1->dev_vendor,
IRONGATE1->stat_cmd,
IRONGATE1->class,
IRONGATE1->htype,
IRONGATE1->rsrvd0[0],
IRONGATE1->rsrvd0[1],
IRONGATE1->busnos,
IRONGATE1->io_baselim_regs,
IRONGATE1->mem_baselim,
IRONGATE1->pfmem_baselim,
IRONGATE1->rsrvd1[0],
IRONGATE1->rsrvd1[1],
IRONGATE1->io_baselim,
IRONGATE1->rsrvd2[0],
IRONGATE1->rsrvd2[1],
IRONGATE1->interrupt );
}
#else
#define irongate_register_dump(x)
#endif
int
irongate_pci_clr_err(void)
{
......@@ -315,11 +177,11 @@ irongate_pci_clr_err(void)
mb();
IRONGATE_jd = IRONGATE0->stat_cmd; /* re-read to force write */
IRONGATE_jd = IRONGATE0->dramms;
printk("Iron dramms %x\n", IRONGATE_jd);
IRONGATE0->dramms = IRONGATE_jd; /* write again clears error bits */
IRONGATE_jd = *IronECC;
printk("Iron ECC %x\n", IRONGATE_jd);
*IronECC = IRONGATE_jd; /* write again clears error bits */
mb();
IRONGATE_jd = IRONGATE0->dramms; /* re-read to force write */
IRONGATE_jd = *IronECC; /* re-read to force write */
/* Clear ALI NMI */
nmi_ctl = inb(0x61);
......@@ -328,28 +190,88 @@ irongate_pci_clr_err(void)
nmi_ctl &= ~0x0c;
outb(nmi_ctl, 0x61);
IRONGATE_jd = IRONGATE0->dramms;
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(__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
reserve_bootmem(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;
IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
irongate_pci_clr_err();
irongate_register_dump(__FUNCTION__);
/*
* HACK: set AGP aperture size to 256MB.
* This should really be changed during PCI probe, when the
* size of the aperture the AGP card wants is known.
*/
printk("irongate_init_arch: AGPVA was 0x%x\n", IRONGATE0->agpva);
IRONGATE0->agpva = (IRONGATE0->agpva & ~0x0000000f) | 0x00000007;
if (amd761)
albacore_init_arch();
irongate_setup_agp();
/*
* Create our single hose.
......@@ -380,89 +302,9 @@ irongate_init_arch(void)
* IO map and AGP support
*/
#include <linux/vmalloc.h>
#include <asm/pgalloc.h>
static inline void
irongate_remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
{
unsigned long end;
unsigned long pfn;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
if (address >= end)
BUG();
pfn = phys_addr >> PAGE_SHIFT;
do {
if (!pte_none(*pte)) {
printk("irongate_remap_area_pte: page already exists\n");
BUG();
}
set_pte(pte, pfn_pte(pfn,
__pgprot(_PAGE_VALID | _PAGE_ASM |
_PAGE_KRE | _PAGE_KWE | flags)));
address += PAGE_SIZE;
pfn++;
pte++;
} while (address && (address < end));
}
static inline int
irongate_remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
unsigned long phys_addr, unsigned long flags)
{
unsigned long end;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
phys_addr -= address;
if (address >= end)
BUG();
do {
pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
if (!pte)
return -ENOMEM;
irongate_remap_area_pte(pte, address, end - address,
address + phys_addr, flags);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
return 0;
}
static int
irongate_remap_area_pages(unsigned long address, unsigned long phys_addr,
unsigned long size, unsigned long flags)
{
pgd_t * dir;
unsigned long end = address + size;
phys_addr -= address;
dir = pgd_offset(&init_mm, address);
flush_cache_all();
if (address >= end)
BUG();
do {
pmd_t *pmd;
pmd = pmd_alloc(&init_mm, dir, address);
if (!pmd)
return -ENOMEM;
if (irongate_remap_area_pmd(pmd, address, end - address,
phys_addr + address, flags))
return -ENOMEM;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} while (address && (address < end));
return 0;
}
#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))
......@@ -477,15 +319,13 @@ irongate_ioremap(unsigned long addr, unsigned long size)
unsigned long vaddr;
unsigned long baddr, last;
u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
unsigned long gart_bus_addr, gart_aper_size;
unsigned long gart_bus_addr;
gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
PCI_BASE_ADDRESS_MEM_MASK;
if (!gart_bus_addr) /* FIXME - there must be a better way!!! */
if (!alpha_agpgart_size)
return addr + IRONGATE_MEM;
gart_aper_size = IRONGATE_DEFAULT_AGP_APER_SIZE; /* FIXME */
gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
PCI_BASE_ADDRESS_MEM_MASK;
/*
* Check for within the AGP aperture...
......@@ -495,7 +335,7 @@ irongate_ioremap(unsigned long addr, unsigned long size)
* Check the AGP area
*/
if (addr >= gart_bus_addr && addr + size - 1 <
gart_bus_addr + gart_aper_size)
gart_bus_addr + alpha_agpgart_size)
break;
/*
......@@ -549,7 +389,7 @@ irongate_ioremap(unsigned long addr, unsigned long size)
cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
if (irongate_remap_area_pages(VMALLOC_VMADDR(vaddr),
if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr),
pte, PAGE_SIZE, 0)) {
printk("AGP ioremap: FAILED to map...\n");
vfree(area->addr);
......
......@@ -31,6 +31,7 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/reboot.h>
#include <linux/bootmem.h>
#include <asm/ptrace.h>
#include <asm/system.h>
......@@ -174,6 +175,70 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
mb();
}
extern void free_reserved_mem(void *, void *);
void __init
nautilus_init_pci(void)
{
struct pci_controller *hose = hose_head;
struct pci_bus *bus;
struct pci_dev *irongate;
unsigned long saved_io_start, saved_io_end;
unsigned long saved_mem_start, saved_mem_end;
unsigned long bus_align, bus_size, pci_mem;
unsigned long memtop = max_low_pfn << PAGE_SHIFT;
/* Scan our single hose. */
bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
hose->bus = bus;
hose->last_busno = bus->subordinate;
/* We're going to size the root bus, so we must
- have a non-NULL PCI device associated with the bus
- preserve hose resources. */
irongate = pci_find_slot(0, 0);
bus->self = irongate;
saved_io_start = bus->resource[0]->start;
saved_io_end = bus->resource[0]->end;
saved_mem_start = bus->resource[1]->start;
saved_mem_end = bus->resource[1]->end;
pci_bus_size_bridges(bus);
/* Don't care about IO. */
bus->resource[0]->start = saved_io_start;
bus->resource[0]->end = saved_io_end;
bus_align = bus->resource[1]->start;
bus_size = bus->resource[1]->end + 1 - bus_align;
/* Align to 16Mb. */
if (bus_align < 0x1000000UL)
bus_align = 0x1000000UL;
/* Restore hose MEM resource. */
bus->resource[1]->start = saved_mem_start;
bus->resource[1]->end = saved_mem_end;
pci_mem = (0x100000000UL - bus_size) & -bus_align;
if (pci_mem < memtop && pci_mem > alpha_mv.min_mem_address) {
free_reserved_mem(__va(alpha_mv.min_mem_address),
__va(pci_mem));
printk("nautilus_init_arch: %ldk freed\n",
(pci_mem - alpha_mv.min_mem_address) >> 10);
}
alpha_mv.min_mem_address = pci_mem;
if ((IRONGATE0->dev_vendor >> 16) > 0x7006) /* Albacore? */
IRONGATE0->pci_mem = pci_mem;
pci_bus_assign_resources(bus);
/* To break the loop in common_swizzle() */
bus->self = NULL;
pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}
/*
* The System Vectors
......@@ -196,7 +261,7 @@ struct alpha_machine_vector nautilus_mv __initmv = {
.init_arch = irongate_init_arch,
.init_irq = nautilus_init_irq,
.init_rtc = common_init_rtc,
.init_pci = common_init_pci,
.init_pci = nautilus_init_pci,
.kill_arch = nautilus_kill_arch,
.pci_map_irq = nautilus_map_irq,
.pci_swizzle = common_swizzle,
......
......@@ -50,13 +50,14 @@ typedef struct {
igcsr32 bacsr10; /* 0x40 - base address chip selects */
igcsr32 bacsr32; /* 0x44 - base address chip selects */
igcsr32 bacsr54; /* 0x48 - base address chip selects */
igcsr32 bacsr54_eccms761; /* 0x48 - 751: base addr. chip selects
761: ECC, mode/status */
igcsr32 rsrvd2[1]; /* 0x4C-0x4F reserved */
igcsr32 drammap; /* 0x50 - address mapping control */
igcsr32 dramtm; /* 0x54 - timing, driver strength */
igcsr32 dramms; /* 0x58 - ECC, mode/status */
igcsr32 dramms; /* 0x58 - DRAM mode/status */
igcsr32 rsrvd3[1]; /* 0x5C-0x5F reserved */
......@@ -73,7 +74,10 @@ typedef struct {
igcsr32 pciarb; /* 0x84 - PCI arbitration control */
igcsr32 pcicfg; /* 0x88 - PCI config status */
igcsr32 rsrvd6[5]; /* 0x8C-0x9F reserved */
igcsr32 rsrvd6[4]; /* 0x8C-0x9B reserved */
igcsr32 pci_mem; /* 0x9C - PCI top of memory,
761 only */
/* AGP (bus 1) control registers */
igcsr32 agpcap; /* 0xA0 - AGP Capability Identifier */
......@@ -102,6 +106,7 @@ typedef struct {
} Irongate1;
extern igcsr32 *IronECC;
/*
* Memory spaces:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment