/*
 *	linux/arch/alpha/kernel/core_pyxis.c
 *
 * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
 *
 * Code common to all PYXIS core logic chips.
 */

#include <linux/types.h>
#include <linux/kernel.h>

#define __EXTERN_INLINE inline
#include <asm/io.h>
#include <asm/core_pyxis.h>
#undef __EXTERN_INLINE

#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/bootmem.h>

#include <asm/ptrace.h>
#include <asm/system.h>

#include "proto.h"
#include "irq_impl.h"
#include "pci_impl.h"


/* NOTE: Herein are back-to-back mb instructions.  They are magic.
   One plausible explanation is that the I/O controller does not properly
   handle the system transaction.  Another involves timing.  Ho hum.  */

/*
 * BIOS32-style PCI interface:
 */

#define DEBUG_CONFIG 0
#if DEBUG_CONFIG
# define DBG_CNF(args)	printk args
#else
# define DBG_CNF(args)
#endif


/*
 * Given a bus, device, and function number, compute resulting
 * configuration space address and setup the PYXIS_HAXR2 register
 * 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.
 *
 * Type 0:
 *
 *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
 *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 *	31:11	Device select bit.
 * 	10:8	Function number
 * 	 7:2	Register number
 *
 * Type 1:
 *
 *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
 *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 *	31:24	reserved
 *	23:16	bus number (8 bits = 128 possible buses)
 *	15:11	Device number (5 bits)
 *	10:8	function number
 *	 7:2	register number
 *  
 * 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_dev *dev, int where, unsigned long *pci_addr,
	     unsigned char *type1)
{
	u8 bus = dev->bus->number;
	u8 device_fn = dev->devfn;

	*type1 = (bus == 0) ? 0 : 1;
	*pci_addr = (bus << 16) | (device_fn << 8) | (where);

	DBG_CNF(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
		 " returning address 0x%p\n"
		 bus, device_fn, where, *pci_addr));

	return 0;
}

static unsigned int
conf_read(unsigned long addr, unsigned char type1)
{
	unsigned long flags;
	unsigned int stat0, value, temp;
	unsigned int pyxis_cfg = 0;

	__save_and_cli(flags);	/* avoid getting hit by machine check */

	/* Reset status register to avoid losing errors.  */
	stat0 = *(vuip)PYXIS_ERR;
	*(vuip)PYXIS_ERR = stat0; mb();
	temp = *(vuip)PYXIS_ERR;  /* re-read to force write */

	/* If Type1 access, must set PYXIS CFG.  */
	if (type1) {
		pyxis_cfg = *(vuip)PYXIS_CFG;
		*(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb();
		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
	}

	mb();
	draina();
	mcheck_expected(0) = 1;
	mcheck_taken(0) = 0;
	mb();

	/* Access configuration space.  */
	value = *(vuip)addr;
	mb();
	mb();  /* magic */

	if (mcheck_taken(0)) {
		mcheck_taken(0) = 0;
		value = 0xffffffffU;
		mb();
	}
	mcheck_expected(0) = 0;
	mb();

	/* If Type1 access, must reset IOC CFG so normal IO space ops work.  */
	if (type1) {
		*(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb();
		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
	}

	__restore_flags(flags);

	DBG_CNF(("conf_read(addr=0x%lx, type1=%d) = %#x\n",
		 addr, type1, value));

	return value;
}

static void
conf_write(unsigned long addr, unsigned int value, unsigned char type1)
{
	unsigned long flags;
	unsigned int stat0, temp;
	unsigned int pyxis_cfg = 0;

	__save_and_cli(flags);	/* avoid getting hit by machine check */

	/* Reset status register to avoid losing errors.  */
	stat0 = *(vuip)PYXIS_ERR;
	*(vuip)PYXIS_ERR = stat0; mb();
	temp = *(vuip)PYXIS_ERR;  /* re-read to force write */

	/* If Type1 access, must set PYXIS CFG.  */
	if (type1) {
		pyxis_cfg = *(vuip)PYXIS_CFG;
		*(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb();
		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
	}

	mb();
	draina();
	mcheck_expected(0) = 1;
	mcheck_taken(0) = 0;
	mb();

	/* Access configuration space.  */
	*(vuip)addr = value;
	mb();
	temp = *(vuip)addr; /* read back to force the write */
	mcheck_expected(0) = 0;
	mb();

	/* If Type1 access, must reset IOC CFG so normal IO space ops work.  */
	if (type1) {
		*(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb();
		temp = *(vuip)PYXIS_CFG;  /* re-read to force write */
	}

	__restore_flags(flags);

	DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n",
		 addr, value, type1));
}

static int
pyxis_read_config_byte(struct pci_dev *dev, int where, u8 *value)
{
	unsigned long addr, pci_addr;
	unsigned char type1;

	if (mk_conf_addr(dev, where, &pci_addr, &type1))
		return PCIBIOS_DEVICE_NOT_FOUND;

	addr = (pci_addr << 5) + 0x00 + PYXIS_CONF;
	*value = conf_read(addr, type1) >> ((where & 3) * 8);
	return PCIBIOS_SUCCESSFUL;
}

static int
pyxis_read_config_word(struct pci_dev *dev, int where, u16 *value)
{
	unsigned long addr, pci_addr;
	unsigned char type1;

	if (mk_conf_addr(dev, where, &pci_addr, &type1))
		return PCIBIOS_DEVICE_NOT_FOUND;

	addr = (pci_addr << 5) + 0x08 + PYXIS_CONF;
	*value = conf_read(addr, type1) >> ((where & 3) * 8);
	return PCIBIOS_SUCCESSFUL;
}

static int
pyxis_read_config_dword(struct pci_dev *dev, int where, u32 *value)
{
	unsigned long addr, pci_addr;
	unsigned char type1;

	if (mk_conf_addr(dev, where, &pci_addr, &type1))
		return PCIBIOS_DEVICE_NOT_FOUND;

	addr = (pci_addr << 5) + 0x18 + PYXIS_CONF;
	*value = conf_read(addr, type1);
	return PCIBIOS_SUCCESSFUL;
}

static int
pyxis_write_config(struct pci_dev *dev, int where, u32 value, long mask)
{
	unsigned long addr, pci_addr;
	unsigned char type1;

	if (mk_conf_addr(dev, where, &pci_addr, &type1))
		return PCIBIOS_DEVICE_NOT_FOUND;

	addr = (pci_addr << 5) + mask + PYXIS_CONF;
	conf_write(addr, value << ((where & 3) * 8), type1);
	return PCIBIOS_SUCCESSFUL;
}

static int 
pyxis_write_config_byte(struct pci_dev *dev, int where, u8 value)
{
	return pyxis_write_config(dev, where, value, 0x00);
}

static int 
pyxis_write_config_word(struct pci_dev *dev, int where, u16 value)
{
	return pyxis_write_config(dev, where, value, 0x08);
}

static int 
pyxis_write_config_dword(struct pci_dev *dev, int where, u32 value)
{
	return pyxis_write_config(dev, where, value, 0x18);
}

struct pci_ops pyxis_pci_ops = 
{
	read_byte:	pyxis_read_config_byte,
	read_word:	pyxis_read_config_word,
	read_dword:	pyxis_read_config_dword,
	write_byte:	pyxis_write_config_byte,
	write_word:	pyxis_write_config_word,
	write_dword:	pyxis_write_config_dword
};

/* Note mask bit is true for ENABLED irqs.  */
static unsigned long cached_irq_mask;

static inline void
pyxis_update_irq_hw(unsigned long mask)
{
	*(vulp)PYXIS_INT_MASK = mask;
	mb();
	*(vulp)PYXIS_INT_MASK;
}

static inline void
pyxis_enable_irq(unsigned int irq)
{
	pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
}

static void
pyxis_disable_irq(unsigned int irq)
{
	pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
}

static unsigned int
pyxis_startup_irq(unsigned int irq)
{
	pyxis_enable_irq(irq);
	return 0;
}

static void
pyxis_end_irq(unsigned int irq)
{
	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
		pyxis_enable_irq(irq);
}

static void
pyxis_mask_and_ack_irq(unsigned int irq)
{
	unsigned long bit = 1UL << (irq - 16);
	unsigned long mask = cached_irq_mask &= ~bit;

	/* Disable the interrupt.  */
	*(vulp)PYXIS_INT_MASK = mask;
	wmb();
	/* Ack PYXIS PCI interrupt.  */
	*(vulp)PYXIS_INT_REQ = bit;
	mb();
	/* Re-read to force both writes.  */
	*(vulp)PYXIS_INT_MASK;
}

static struct hw_interrupt_type pyxis_irq_type = {
	typename:	"PYXIS",
	startup:	pyxis_startup_irq,
	shutdown:	pyxis_disable_irq,
	enable:		pyxis_enable_irq,
	disable:	pyxis_disable_irq,
	ack:		pyxis_mask_and_ack_irq,
	end:		pyxis_end_irq,
};

void 
pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
{
	unsigned long pld;
	unsigned int i;

	/* Read the interrupt summary register of PYXIS */
	pld = *(vulp)PYXIS_INT_REQ;
	pld &= cached_irq_mask;

	/*
	 * Now for every possible bit set, work through them and call
	 * the appropriate interrupt handler.
	 */
	while (pld) {
		i = ffz(~pld);
		pld &= pld - 1; /* clear least bit set */
		if (i == 7)
			isa_device_interrupt(vector, regs);
		else
			handle_irq(16+i, regs);
	}
}

void __init
init_pyxis_irqs(unsigned long ignore_mask)
{
	long i;

	*(vulp)PYXIS_INT_MASK = 0;		/* disable all */
	*(vulp)PYXIS_INT_REQ  = -1;		/* flush all */
	mb();

	/* Send -INTA pulses to clear any pending interrupts ...*/
	*(vuip) PYXIS_IACK_SC;

	for (i = 16; i < 48; ++i) {
		if ((ignore_mask >> i) & 1)
			continue;
		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
		irq_desc[i].handler = &pyxis_irq_type;
	}

	setup_irq(16+7, &isa_cascade_irqaction);
}

void
pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
{
	wmb();
	*(vip)PYXIS_TBIA = 3;	/* Flush all locked and unlocked.  */
	mb();
}

/*
 * Pass 1 and 2 have a broken scatter-gather tlb -- it cannot be invalidated.
 * To work around this problem, we allocate mappings, and put the chip into
 * DMA loopback mode to read a garbage page.  This works by causing TLB
 * misses, causing old entries to be purged to make room for the new entries
 * coming in for the garbage page.
 * 
 * Thanks to NetBSD sources for pointing out this bug.  What a pain.
 */

static unsigned long broken_tbi_addr;

#define BROKEN_TBI_READS 12

static void
pyxis_broken_pci_tbi(struct pci_controler *hose,
		     dma_addr_t start, dma_addr_t end)
{
	unsigned long flags;
	unsigned long bus_addr;
	unsigned int ctrl;
	long i;

	__save_and_cli(flags);

	/* Put the chip into PCI loopback mode.  */
	mb();
	ctrl = *(vuip)PYXIS_CTRL;
	*(vuip)PYXIS_CTRL = ctrl | 4;
	mb();
	*(vuip)PYXIS_CTRL;
	mb();

	/* Read from PCI dense memory space at TBI_ADDR, skipping 64k
	   on each read.  This forces SG TLB misses.  It appears that
	   the TLB entries are "not quite LRU", meaning that we need
	   to read more times than there are actual tags.  */

	bus_addr = broken_tbi_addr;
	for (i = 0; i < BROKEN_TBI_READS; ++i, bus_addr += 64*1024)
		pyxis_readl(bus_addr);

	/* Restore normal PCI operation.  */
	mb();
	*(vuip)PYXIS_CTRL = ctrl;
	mb();
	*(vuip)PYXIS_CTRL;
	mb();

	__restore_flags(flags);
}

static void __init
pyxis_enable_broken_tbi(struct pci_iommu_arena *arena)
{
	void *page;
	unsigned long *ppte, ofs, pte;
	long i, npages;

	page = alloc_bootmem_pages(PAGE_SIZE);
	pte = (virt_to_phys(page) >> (PAGE_SHIFT - 1)) | 1;
	npages = (BROKEN_TBI_READS + 1) * 64*1024 / PAGE_SIZE;

	ofs = iommu_arena_alloc(arena, npages);
	ppte = arena->ptes + ofs;
	for (i = 0; i < npages; ++i)
		ppte[i] = pte;

	broken_tbi_addr = pyxis_ioremap(arena->dma_base + ofs*PAGE_SIZE);
	alpha_mv.mv_pci_tbi = pyxis_broken_pci_tbi;

	printk("PYXIS: Enabling broken tbia workaround.\n");
}

void __init
pyxis_init_arch(void)
{
	struct pci_controler *hose;
	unsigned int temp;

	/* Set up error reporting. Make sure CPU_PE is OFF in the mask.  */
	temp = *(vuip)PYXIS_ERR_MASK;
	*(vuip)PYXIS_ERR_MASK = temp & ~4;

	/* Enable master/target abort.  */
	temp = *(vuip)PYXIS_ERR;
	*(vuip)PYXIS_ERR = temp | 0x180;

	/* Clear the PYXIS_CFG register, which gets used  for PCI Config
	   Space accesses.  That is the way we want to use it, and we do
	   not want to depend on what ARC or SRM might have left behind.  */
	*(vuip)PYXIS_CFG = 0;
 
	/* Zero the HAEs.  */
	*(vuip)PYXIS_HAE_MEM = 0;
	*(vuip)PYXIS_HAE_IO = 0;

	/* Finally, check that the PYXIS_CTRL1 has IOA_BEN set for
	   enabling byte/word PCI bus space(s) access.  */
	temp = *(vuip)PYXIS_CTRL1;
	*(vuip)PYXIS_CTRL1 = temp | 1;

	/* Syncronize with all previous changes.  */
	mb();
	*(vuip)PYXIS_REV;

 	/*
	 * Create our single hose.
	 */

	hose = alloc_pci_controler();
	hose->io_space = &ioport_resource;
	hose->mem_space = &iomem_resource;
	hose->config_space = PYXIS_CONF;
	hose->index = 0;

	/*
	 * Set up the PCI to main memory translation windows.
	 *
	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
	 * Window 1 is scatter-gather 128MB at 3GB
	 * Window 2 is direct access 1GB at 1GB
	 * Window 3 is direct access 1GB at 2GB
	 * ??? We ought to scale window 1 with memory.
	 *
	 * We must actually use 2 windows to direct-map the 2GB space,
	 * because of an idiot-syncrasy of the CYPRESS chip.  It may
	 * respond to a PCI bus address in the last 1MB of the 4GB
	 * address range.
	 */

#if 1
	/* ??? There's some bit of syncronization wrt writing new tlb
	   entries that's missing.  Sometimes it works, sometimes invalid
	   tlb machine checks, sometimes hard lockup.  And this just within
	   the boot sequence.

	   I've tried extra memory barriers, extra alignment, pyxis
	   register reads, tlb flushes, and loopback tlb accesses.

	   I guess the pyxis revision in the sx164 is just too buggy...  */

	hose->sg_isa = hose->sg_pci = NULL;
	__direct_map_base = 0x40000000;
	__direct_map_size = 0x80000000;

	*(vuip)PYXIS_W0_BASE = 0x40000000 | 1;
	*(vuip)PYXIS_W0_MASK = (0x40000000 - 1) & 0xfff00000;
	*(vuip)PYXIS_T0_BASE = 0;

	*(vuip)PYXIS_W1_BASE = 0x80000000 | 1;
	*(vuip)PYXIS_W1_MASK = (0x40000000 - 1) & 0xfff00000;
	*(vuip)PYXIS_T1_BASE = 0;

	*(vuip)PYXIS_W2_BASE = 0;
	*(vuip)PYXIS_W3_BASE = 0;

	alpha_mv.mv_pci_tbi = NULL;
	mb();
#else
	/* ??? NetBSD hints that page tables must be aligned to 32K,
	   possibly due to a hardware bug.  This is over-aligned
	   from the 8K alignment one would expect for an 8MB window. 
	   No description of what CIA revisions affected.  */
	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0x08000);
	hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0x20000);
	__direct_map_base = 0x40000000;
	__direct_map_size = 0x80000000;

	*(vuip)PYXIS_W0_BASE = hose->sg_isa->dma_base | 3;
	*(vuip)PYXIS_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000;
	*(vuip)PYXIS_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2;

	*(vuip)PYXIS_W1_BASE = hose->sg_pci->dma_base | 3;
	*(vuip)PYXIS_W1_MASK = (hose->sg_pci->size - 1) & 0xfff00000;
	*(vuip)PYXIS_T1_BASE = virt_to_phys(hose->sg_pci->ptes) >> 2;

	*(vuip)PYXIS_W2_BASE = 0x40000000 | 1;
	*(vuip)PYXIS_W2_MASK = (0x40000000 - 1) & 0xfff00000;
	*(vuip)PYXIS_T2_BASE = 0;

	*(vuip)PYXIS_W3_BASE = 0x80000000 | 1;
	*(vuip)PYXIS_W3_MASK = (0x40000000 - 1) & 0xfff00000;
	*(vuip)PYXIS_T3_BASE = 0;

	/* Pass 1 and 2 (ie revision <= 1) have a broken TBIA.  See the
	   complete description next to pyxis_broken_pci_tbi for details.  */
	if ((*(vuip)PYXIS_REV & 0xff) <= 1)
		pyxis_enable_broken_tbi(hose->sg_pci);

	alpha_mv.mv_pci_tbi(hose, 0, -1);
#endif
}

static inline void
pyxis_pci_clr_err(void)
{
	unsigned int tmp;

	tmp = *(vuip)PYXIS_ERR;
	*(vuip)PYXIS_ERR = tmp;
	mb();
	*(vuip)PYXIS_ERR;  /* re-read to force write */
}

void
pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
		    struct pt_regs * regs)
{
	int expected;

	/* Clear the error before reporting anything.  */
	mb();
	mb();  /* magic */
	draina();
	pyxis_pci_clr_err();
	wrmces(0x7);
	mb();

	expected = mcheck_expected(0);
	if (!expected && vector == 0x660) {
		struct el_common *com;
		struct el_common_EV5_uncorrectable_mcheck *ev5;
		struct el_PYXIS_sysdata_mcheck *pyxis;

		com = (void *)la_ptr;
		ev5 = (void *)(la_ptr + com->proc_offset);
		pyxis = (void *)(la_ptr + com->sys_offset);

		if (com->code == 0x202) {
			printk(KERN_CRIT "PYXIS PCI machine check: err0=%08x "
			       "err1=%08x err2=%08x\n",
			       (int) pyxis->pci_err0, (int) pyxis->pci_err1,
			       (int) pyxis->pci_err2);
			expected = 1;
		}
	}
	process_mcheck_info(vector, la_ptr, regs, "PYXIS", expected);
}
