/* $Id: sbus.c,v 1.19 2002/01/23 11:27:32 davem Exp $
* sbus.c: UltraSparc SBUS controller support.
*
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/page.h>
#include <asm/sbus.h>
#include <asm/io.h>
#include <asm/upa.h>
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/starfire.h>
#include "iommu_common.h"
#define MAP_BASE ((u32)0xc0000000)
struct sbus_info {
struct iommu iommu;
struct strbuf strbuf;
};
/* Offsets from iommu_regs */
#define SYSIO_IOMMUREG_BASE 0x2400UL
#define IOMMU_CONTROL (0x2400UL - 0x2400UL) /* IOMMU control register */
#define IOMMU_TSBBASE (0x2408UL - 0x2400UL) /* TSB base address register */
#define IOMMU_FLUSH (0x2410UL - 0x2400UL) /* IOMMU flush register */
#define IOMMU_VADIAG (0x4400UL - 0x2400UL) /* SBUS virtual address diagnostic */
#define IOMMU_TAGCMP (0x4408UL - 0x2400UL) /* TLB tag compare diagnostics */
#define IOMMU_LRUDIAG (0x4500UL - 0x2400UL) /* IOMMU LRU queue diagnostics */
#define IOMMU_TAGDIAG (0x4580UL - 0x2400UL) /* TLB tag diagnostics */
#define IOMMU_DRAMDIAG (0x4600UL - 0x2400UL) /* TLB data RAM diagnostics */
#define IOMMU_DRAM_VALID (1UL << 30UL)
static void __iommu_flushall(struct iommu *iommu)
{
unsigned long tag;
int entry;
tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);
for (entry = 0; entry < 16; entry++) {
upa_writeq(0, tag);
tag += 8UL;
}
upa_readq(iommu->write_complete_reg);
}
/* Offsets from strbuf_regs */
#define SYSIO_STRBUFREG_BASE 0x2800UL
#define STRBUF_CONTROL (0x2800UL - 0x2800UL) /* Control */
#define STRBUF_PFLUSH (0x2808UL - 0x2800UL) /* Page flush/invalidate */
#define STRBUF_FSYNC (0x2810UL - 0x2800UL) /* Flush synchronization */
#define STRBUF_DRAMDIAG (0x5000UL - 0x2800UL) /* data RAM diagnostic */
#define STRBUF_ERRDIAG (0x5400UL - 0x2800UL) /* error status diagnostics */
#define STRBUF_PTAGDIAG (0x5800UL - 0x2800UL) /* Page tag diagnostics */
#define STRBUF_LTAGDIAG (0x5900UL - 0x2800UL) /* Line tag diagnostics */
#define STRBUF_TAG_VALID 0x02UL
static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction)
{
unsigned long n;
int limit;
n = npages;
while (n--)
upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush);
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
* to be performed.
*/
if (direction == SBUS_DMA_TODEVICE)
return;
*(strbuf->strbuf_flushflag) = 0UL;
/* Whoopee cushion! */
upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync);
upa_readq(iommu->write_complete_reg);
limit = 100000;
while (*(strbuf->strbuf_flushflag) == 0UL) {
limit--;
if (!limit)
break;
udelay(1);
rmb();
}
if (!limit)
printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout "
"vaddr[%08x] npages[%ld]\n",
base, npages);
}
/* Based largely upon the ppc64 iommu allocator. */
static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages)
{
struct iommu_arena *arena = &iommu->arena;
unsigned long n, i, start, end, limit;
int pass;
limit = arena->limit;
start = arena->hint;
pass = 0;
again:
n = find_next_zero_bit(arena