All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip
@ 2005-02-28 23:58 Bruce Losure
  2005-03-02  4:47 ` Christoph Hellwig
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Bruce Losure @ 2005-02-28 23:58 UTC (permalink / raw)
  To: linux-ia64

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/02/28 17:49:23-06:00 blosure@attica.americas.sgi.com 
#   Add tio cx port infrastructure and FPGA core services driver
# 
# include/asm-ia64/sn/addrs.h
#   2005/02/28 17:49:11-06:00 blosure@attica.americas.sgi.com +2 -0
#   Add macros for TIO address generation
# 
# drivers/char/Makefile
#   2005/02/28 17:49:11-06:00 blosure@attica.americas.sgi.com +2 -0
#   Add tiocx.o and mbcs.o
# 
# drivers/char/Kconfig
#   2005/02/28 17:49:11-06:00 blosure@attica.americas.sgi.com +14 -0
#   Add config options for tiocx infrastructure and core services driver
# 
# arch/ia64/configs/sn2_defconfig
#   2005/02/28 17:49:11-06:00 blosure@attica.americas.sgi.com +2 -0
#   Add config options for tiocx infrastructure and core services driver
# 
# drivers/char/tiocx.h
#   2005/02/28 12:18:17-06:00 blosure@attica.americas.sgi.com +71 -0
# 
# drivers/char/tiocx.h
#   2005/02/28 12:18:17-06:00 blosure@attica.americas.sgi.com +0 -0
#   BitKeeper file /data/lwork/attica1/blosure/bktrees/ci_211/drivers/char/tiocx.h
# 
# drivers/char/tiocx.c
#   2005/02/28 12:18:16-06:00 blosure@attica.americas.sgi.com +555 -0
# 
# drivers/char/tiocx.c
#   2005/02/28 12:18:16-06:00 blosure@attica.americas.sgi.com +0 -0
#   BitKeeper file /data/lwork/attica1/blosure/bktrees/ci_211/drivers/char/tiocx.c
# 
# drivers/char/mbcs.h
#   2005/02/28 12:18:09-06:00 blosure@attica.americas.sgi.com +549 -0
# 
# drivers/char/mbcs.h
#   2005/02/28 12:18:09-06:00 blosure@attica.americas.sgi.com +0 -0
#   BitKeeper file /data/lwork/attica1/blosure/bktrees/ci_211/drivers/char/mbcs.h
# 
# drivers/char/mbcs.c
#   2005/02/28 12:18:08-06:00 blosure@attica.americas.sgi.com +855 -0
# 
# drivers/char/mbcs.c
#   2005/02/28 12:18:08-06:00 blosure@attica.americas.sgi.com +0 -0
#   BitKeeper file /data/lwork/attica1/blosure/bktrees/ci_211/drivers/char/mbcs.c
# 
diff -Nru a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
--- a/arch/ia64/configs/sn2_defconfig	2005-02-28 17:50:10 -06:00
+++ b/arch/ia64/configs/sn2_defconfig	2005-02-28 17:50:10 -06:00
@@ -573,6 +573,8 @@
 # CONFIG_N_HDLC is not set
 # CONFIG_STALDRV is not set
 CONFIG_SGI_SNSC=y
+# CONFIG_SGI_TIOCX is not set
+# CONFIG_SGI_MBCS is not set
 
 #
 # Serial drivers
diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig
--- a/drivers/char/Kconfig	2005-02-28 17:50:10 -06:00
+++ b/drivers/char/Kconfig	2005-02-28 17:50:10 -06:00
@@ -416,6 +416,20 @@
 	  controller communication from user space (you want this!),
 	  say Y.  Otherwise, say N.
 
+config SGI_TIOCX
+       bool "SGI TIO CX driver support"
+       depends on (IA64_SGI_SN2 || IA64_GENERIC)
+       help
+         If you have an SGI Altix and you have fpga devices attached
+         to your TIO, say Y here, otherwise say N.
+
+config SGI_MBCS
+       tristate "SGI FPGA Core Services driver support"
+       depends on (IA64_SGI_SN2 || IA64_GENERIC)
+       help
+         If you have an SGI Altix with an attached SABrick
+         say Y or M here, otherwise say N.
+
 source "drivers/serial/Kconfig"
 
 config UNIX98_PTYS
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	2005-02-28 17:50:10 -06:00
+++ b/drivers/char/Makefile	2005-02-28 17:50:10 -06:00
@@ -48,6 +48,8 @@
 obj-$(CONFIG_VIOCONS) += viocons.o
 obj-$(CONFIG_VIOTAPE)		+= viotape.o
 obj-$(CONFIG_HVCS)		+= hvcs.o
+obj-$(CONFIG_SGI_TIOCX)		+= tiocx.o
+obj-$(CONFIG_SGI_MBCS)		+= mbcs.o
 
 obj-$(CONFIG_PRINTER) += lp.o
 obj-$(CONFIG_TIPAR) += tipar.o
diff -Nru a/drivers/char/mbcs.c b/drivers/char/mbcs.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/mbcs.c	2005-02-28 17:50:10 -06:00
@@ -0,0 +1,855 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+/*
+ *	MOATB Core Services driver.
+ */
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/uio.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/intr.h>
+#include "tiocx.h"
+#include "mbcs.h"
+
+#define MBCS_DEBUG 0
+#if MBCS_DEBUG
+#define DBG(fmt...)    printk(KERN_ALERT fmt)
+#else
+#define DBG(fmt...)
+#endif
+int mbcs_major = 0;
+
+extern struct bus_type tiocx_bus_type;
+
+/*
+ * file operations
+ */
+struct file_operations mbcs_ops = {
+	.open = mbcs_open,
+	.llseek = mbcs_sram_llseek,
+	.read = mbcs_sram_read,
+	.write = mbcs_sram_write,
+	.mmap = mbcs_gscr_mmap,
+};
+
+struct mbcs_callback_arg {
+	int minor;
+	struct cx_dev *cx_dev;
+};
+
+static void getDma_init(struct getDma_soft_s *pGetDma)
+{
+	/* setup engine parameters */
+	pGetDma->hostAddr = 0;
+	pGetDma->localAddr = 0;
+	pGetDma->bytes = 0;
+	pGetDma->DoneAmoEnable = 0;
+	pGetDma->DoneIntEnable = 1;
+	pGetDma->peerIO = 0;
+	pGetDma->amoHostDest = 0;
+	pGetDma->amoModType = 0;
+	pGetDma->intrHostDest = 0;
+	pGetDma->intrVector = 0;
+}
+
+static void putDma_init(struct putDma_soft_s *pPutDma)
+{
+	/* setup engine parameters */
+	pPutDma->hostAddr = 0;
+	pPutDma->localAddr = 0;
+	pPutDma->bytes = 0;
+	pPutDma->DoneAmoEnable = 0;
+	pPutDma->DoneIntEnable = 1;
+	pPutDma->peerIO = 0;
+	pPutDma->amoHostDest = 0;
+	pPutDma->amoModType = 0;
+	pPutDma->intrHostDest = 0;
+	pPutDma->intrVector = 0;
+}
+
+static void algo_init(struct algo_soft_s *algo_soft)
+{
+	algo_soft->amoHostDest = 0;
+	algo_soft->amoModType = 0;
+	algo_soft->intrHostDest = 0;
+	algo_soft->intrVector = 0;
+	algo_soft->algoStepCount = 0;
+}
+
+static void getDma_set(void *mmr,
+		       uint64_t hostAddr,
+		       uint64_t localAddr,
+		       uint64_t localRamSel,
+		       uint64_t numPkts,
+		       uint64_t amoEnable,
+		       uint64_t intrEnable,
+		       uint64_t peerIO,
+		       uint64_t amoHostDest,
+		       uint64_t amoModType, uint64_t intrHostDest,
+		       uint64_t intrVector)
+{
+	union dma_control_s rdma_control;
+	union dma_amo_dest_s amo_dest;
+	union intr_dest_s intr_dest;
+	union dma_localaddr_s local_addr;
+	union dma_hostaddr_s host_addr;
+
+	rdma_control.dma_control_reg = 0;
+	amo_dest.dma_amo_dest_reg = 0;
+	intr_dest.intr_dest_reg = 0;
+	local_addr.dma_localaddr_reg = 0;
+	host_addr.dma_hostaddr_reg = 0;
+
+	host_addr.dma_sys_addr = hostAddr;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
+
+	local_addr.dma_ram_addr = localAddr;
+	local_addr.dma_ram_sel = localRamSel;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
+
+	rdma_control.dma_op_length = numPkts;
+	rdma_control.done_amo_en = amoEnable;
+	rdma_control.done_int_en = intrEnable;
+	rdma_control.pio_mem_n = peerIO;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_CTRL, rdma_control.dma_control_reg);
+
+	amo_dest.dma_amo_sys_addr = amoHostDest;
+	amo_dest.dma_amo_mod_type = amoModType;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
+
+	intr_dest.address = intrHostDest;
+	intr_dest.int_vector = intrVector;
+	MBCS_MMR_SET(mmr, MBCS_RD_DMA_INT_DEST, intr_dest.intr_dest_reg);
+
+}
+
+static void putDma_set(void *mmr,
+		       uint64_t hostAddr,
+		       uint64_t localAddr,
+		       uint64_t localRamSel,
+		       uint64_t numPkts,
+		       uint64_t amoEnable,
+		       uint64_t intrEnable,
+		       uint64_t peerIO,
+		       uint64_t amoHostDest,
+		       uint64_t amoModType,
+		       uint64_t intrHostDest, uint64_t intrVector)
+{
+	union dma_control_s wdma_control;
+	union dma_amo_dest_s amo_dest;
+	union intr_dest_s intr_dest;
+	union dma_localaddr_s local_addr;
+	union dma_hostaddr_s host_addr;
+
+	wdma_control.dma_control_reg = 0;
+	amo_dest.dma_amo_dest_reg = 0;
+	intr_dest.intr_dest_reg = 0;
+	local_addr.dma_localaddr_reg = 0;
+	host_addr.dma_hostaddr_reg = 0;
+
+	host_addr.dma_sys_addr = hostAddr;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_SYS_ADDR, host_addr.dma_hostaddr_reg);
+
+	local_addr.dma_ram_addr = localAddr;
+	local_addr.dma_ram_sel = localRamSel;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_LOC_ADDR, local_addr.dma_localaddr_reg);
+
+	wdma_control.dma_op_length = numPkts;
+	wdma_control.done_amo_en = amoEnable;
+	wdma_control.done_int_en = intrEnable;
+	wdma_control.pio_mem_n = peerIO;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_CTRL, wdma_control.dma_control_reg);
+
+	amo_dest.dma_amo_sys_addr = amoHostDest;
+	amo_dest.dma_amo_mod_type = amoModType;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_AMO_DEST, amo_dest.dma_amo_dest_reg);
+
+	intr_dest.address = intrHostDest;
+	intr_dest.int_vector = intrVector;
+	MBCS_MMR_SET(mmr, MBCS_WR_DMA_INT_DEST, intr_dest.intr_dest_reg);
+
+}
+
+static void algo_set(void *mmr,
+		     uint64_t amoHostDest,
+		     uint64_t amoModType,
+		     uint64_t intrHostDest,
+		     uint64_t intrVector, uint64_t algoStepCount)
+{
+	union dma_amo_dest_s amo_dest;
+	union intr_dest_s intr_dest;
+	union algo_step_s step;
+
+	step.algo_step_reg = 0;
+	intr_dest.intr_dest_reg = 0;
+	amo_dest.dma_amo_dest_reg = 0;
+
+	amo_dest.dma_amo_sys_addr = amoHostDest;
+	amo_dest.dma_amo_mod_type = amoModType;
+	MBCS_MMR_SET(mmr, MBCS_ALG_AMO_DEST, amo_dest.dma_amo_dest_reg);
+
+	intr_dest.address = intrHostDest;
+	intr_dest.int_vector = intrVector;
+	MBCS_MMR_SET(mmr, MBCS_ALG_INT_DEST, intr_dest.intr_dest_reg);
+
+	step.alg_step_cnt = algoStepCount;
+	MBCS_MMR_SET(mmr, MBCS_ALG_STEP, step.algo_step_reg);
+}
+
+static int getDma_start(struct mbcs_soft_s *soft)
+{
+	void *mmr_base;
+	struct getDma_soft_s *pGetDma;
+	uint64_t numPkts;
+	union cm_control_s cm_control;
+
+	mmr_base = soft->mmr_base;
+	pGetDma = &soft->getDma;
+
+	/* check that host address got setup */
+	if (!pGetDma->hostAddr)
+		return -1;
+
+	numPkts +	    (pGetDma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
+
+	/* program engine */
+	getDma_set(mmr_base, tiocx_dma_addr(pGetDma->hostAddr),
+		   pGetDma->localAddr,
+		   (pGetDma->localAddr < MB2) ? 0 :
+		   (pGetDma->localAddr < MB4) ? 1 :
+		   (pGetDma->localAddr < MB6) ? 2 : 3,
+		   numPkts,
+		   pGetDma->DoneAmoEnable,
+		   pGetDma->DoneIntEnable,
+		   pGetDma->peerIO,
+		   pGetDma->amoHostDest,
+		   pGetDma->amoModType,
+		   pGetDma->intrHostDest, pGetDma->intrVector);
+
+	/* start engine */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.rd_dma_go = 1;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return 0;
+
+}
+
+static int putDma_start(struct mbcs_soft_s *soft)
+{
+	void *mmr_base;
+	struct putDma_soft_s *pPutDma;
+	uint64_t numPkts;
+	union cm_control_s cm_control;
+
+	mmr_base = soft->mmr_base;
+	pPutDma = &soft->putDma;
+
+	/* check that host address got setup */
+	if (!pPutDma->hostAddr)
+		return -1;
+
+	numPkts +	    (pPutDma->bytes + (MBCS_CACHELINE_SIZE - 1)) / MBCS_CACHELINE_SIZE;
+
+	/* program engine */
+	putDma_set(mmr_base, tiocx_dma_addr(pPutDma->hostAddr),
+		   pPutDma->localAddr,
+		   (pPutDma->localAddr < MB2) ? 0 :
+		   (pPutDma->localAddr < MB4) ? 1 :
+		   (pPutDma->localAddr < MB6) ? 2 : 3,
+		   numPkts,
+		   pPutDma->DoneAmoEnable,
+		   pPutDma->DoneIntEnable,
+		   pPutDma->peerIO,
+		   pPutDma->amoHostDest,
+		   pPutDma->amoModType,
+		   pPutDma->intrHostDest, pPutDma->intrVector);
+
+	/* start engine */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.wr_dma_go = 1;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return 0;
+
+}
+
+static int algo_start(struct mbcs_soft_s *soft)
+{
+	struct algo_soft_s *algo_soft = &soft->algo;
+	void *mmr_base = soft->mmr_base;
+	union cm_control_s cm_control;
+
+	algo_set(mmr_base,
+		 algo_soft->amoHostDest,
+		 algo_soft->amoModType,
+		 algo_soft->intrHostDest,
+		 algo_soft->intrVector, algo_soft->algoStepCount);
+
+	/* start algorithm */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.alg_done_int_en = 1;
+	cm_control.alg_go = 1;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return 0;
+}
+
+static ssize_t
+do_mbcs_sram_dmawrite(struct mbcs_soft_s *soft, uint64_t hostAddr,
+		      size_t len, loff_t * off)
+{
+	int rv = 0;
+
+	soft->putDma.hostAddr = hostAddr;
+	soft->putDma.localAddr = *off;
+	soft->putDma.bytes = len;
+
+	if (putDma_start(soft) < 0) {
+		DBG(KERN_ALERT "do_mbcs_sram_dmawrite: putDma_start failed\n");
+		return -EAGAIN;
+	}
+
+	interruptible_sleep_on(&soft->dmawrite_queue);
+
+	rv = len;
+	*off += len;
+
+	return rv;
+}
+
+static ssize_t
+do_mbcs_sram_dmaread(struct mbcs_soft_s *soft, uint64_t hostAddr,
+		     size_t len, loff_t * off)
+{
+	int rv = 0;
+
+	soft->getDma.hostAddr = hostAddr;
+	soft->getDma.localAddr = *off;
+	soft->getDma.bytes = len;
+
+	if (getDma_start(soft) < 0) {
+		DBG(KERN_ALERT "mbcs_strategy: getDma_start failed\n");
+		return -EAGAIN;
+	}
+
+	interruptible_sleep_on(&soft->dmaread_queue);
+
+	rv = len;
+	*off += len;
+
+	return rv;
+}
+
+static int mbcs_find_device(struct device *dev, void *cb_arg)
+{
+	struct cx_dev *cx_dev;
+	struct mbcs_callback_arg *cba;
+	struct mbcs_soft_s *soft;
+
+	cx_dev = to_cx_dev(dev);
+	cba = cb_arg;
+	soft = (struct mbcs_soft_s *)cx_dev->soft;
+	if (soft = NULL)
+		return 0;
+
+	if (soft->nasid = cba->minor) {
+		cba->cx_dev = cx_dev;
+		return 1;
+	}
+
+	return 0;
+}
+
+int mbcs_open(struct inode *ip, struct file *fp)
+{
+	struct mbcs_callback_arg cba;
+
+	if (ip = NULL || fp = NULL)
+		return -EINVAL;
+
+	cba.minor = iminor(ip);
+
+	cba.cx_dev = NULL;
+	bus_for_each_dev(&tiocx_bus_type, NULL, &cba, mbcs_find_device);
+
+	if (cba.cx_dev = NULL)
+		return -ENODEV;
+
+	fp->private_data = cba.cx_dev;
+
+	return 0;
+}
+
+ssize_t mbcs_sram_read(struct file * fp, char *buf, size_t len, loff_t * off)
+{
+	struct cx_dev *cx_dev = fp->private_data;
+	struct mbcs_soft_s *soft = cx_dev->soft;
+	uint64_t hostAddr;
+	int rv = 0;
+
+	hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
+	if (hostAddr = 0)
+		return -ENOMEM;
+
+	rv = do_mbcs_sram_dmawrite(soft, hostAddr, len, off);
+	if (rv < 0)
+		goto exit;
+
+	if (copy_to_user(buf, (void *)hostAddr, len))
+		rv = -EFAULT;
+
+      exit:
+	free_pages(hostAddr, get_order(len));
+
+	return rv;
+}
+
+ssize_t
+mbcs_sram_write(struct file * fp, const char *buf, size_t len, loff_t * off)
+{
+	struct cx_dev *cx_dev = fp->private_data;
+	struct mbcs_soft_s *soft = cx_dev->soft;
+	uint64_t hostAddr;
+	int rv = 0;
+
+	hostAddr = __get_dma_pages(GFP_KERNEL, get_order(len));
+	if (hostAddr = 0)
+		return -ENOMEM;
+
+	if (copy_from_user((void *)hostAddr, buf, len)) {
+		rv = -EFAULT;
+		goto exit;
+	}
+
+	rv = do_mbcs_sram_dmaread(soft, hostAddr, len, off);
+
+      exit:
+	free_pages(hostAddr, get_order(len));
+
+	return rv;
+}
+
+loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
+{
+	loff_t newpos;
+
+	switch (whence) {
+	case 0:		/* SEEK_SET */
+		newpos = off;
+		break;
+
+	case 1:		/* SEEK_CUR */
+		newpos = filp->f_pos + off;
+		break;
+
+	case 2:		/* SEEK_END */
+		newpos = MBCS_SRAM_SIZE + off;
+		break;
+
+	default:		/* can't happen */
+		return -EINVAL;
+	}
+
+	if (newpos < 0)
+		return -EINVAL;
+
+	filp->f_pos = newpos;
+
+	return newpos;
+}
+
+static uint64_t mbcs_pioaddr(struct mbcs_soft_s *soft, uint64_t offset)
+{
+	uint64_t mmr_base;
+
+	mmr_base = (uint64_t) (soft->mmr_base + offset);
+
+	return mmr_base;
+}
+
+static void mbcs_debug_pioaddr_set(struct mbcs_soft_s *soft)
+{
+	soft->debug_addr = mbcs_pioaddr(soft, MBCS_DEBUG_START);
+}
+
+static void mbcs_gscr_pioaddr_set(struct mbcs_soft_s *soft)
+{
+	soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
+}
+
+int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
+{
+	struct cx_dev *cx_dev = fp->private_data;
+	struct mbcs_soft_s *soft = cx_dev->soft;
+
+	if (vma->vm_pgoff != 0)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */
+	if (remap_pfn_range(vma,
+			    vma->vm_start,
+			    __pa(soft->gscr_addr) >> PAGE_SHIFT,
+			    PAGE_SIZE,
+			    vma->vm_page_prot))
+		return -EAGAIN;
+
+	return 0;
+}
+
+/**
+ * mbcs_completion_intr_handler - Primary completion handler.
+ * @irq: irq
+ * @arg: soft struct for device
+ * @ep: regs
+ *
+ */
+static irqreturn_t
+mbcs_completion_intr_handler(int irq, void *arg, struct pt_regs *ep)
+{
+	struct mbcs_soft_s *soft = (struct mbcs_soft_s *)arg;
+	void *mmr_base;
+	union cm_status_s cm_status;
+	union cm_control_s cm_control;
+
+	mmr_base = soft->mmr_base;
+	cm_status.cm_status_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_STATUS);
+
+	if (cm_status.rd_dma_done) {
+		/* stop dma-read engine, clear status */
+		cm_control.cm_control_reg +		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+		cm_control.rd_dma_clr = 1;
+		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
+			     cm_control.cm_control_reg);
+		wake_up(&soft->dmaread_queue);
+	}
+	if (cm_status.wr_dma_done) {
+		/* stop dma-write engine, clear status */
+		cm_control.cm_control_reg +		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+		cm_control.wr_dma_clr = 1;
+		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
+			     cm_control.cm_control_reg);
+		wake_up(&soft->dmawrite_queue);
+	}
+	if (cm_status.alg_done) {
+		/* clear status */
+		cm_control.cm_control_reg +		    MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+		cm_control.alg_done_clr = 1;
+		MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL,
+			     cm_control.cm_control_reg);
+		wake_up(&soft->algo_queue);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * mbcs_intr_alloc - Allocate interrupts.
+ * @dev: device pointer
+ *
+ */
+static int mbcs_intr_alloc(struct cx_dev *dev)
+{
+	struct sn_irq_info *sn_irq;
+	struct mbcs_soft_s *soft;
+	struct getDma_soft_s *getDma;
+	struct putDma_soft_s *putDma;
+	struct algo_soft_s *algo;
+
+	soft = dev->soft;
+	getDma = &soft->getDma;
+	putDma = &soft->putDma;
+	algo = &soft->algo;
+
+	soft->get_sn_irq = NULL;
+	soft->put_sn_irq = NULL;
+	soft->algo_sn_irq = NULL;
+
+	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
+	if (sn_irq = NULL)
+		return -EAGAIN;
+	soft->get_sn_irq = sn_irq;
+	getDma->intrHostDest = sn_irq->irq_xtalkaddr;
+	getDma->intrVector = sn_irq->irq_irq;
+	if (request_irq(sn_irq->irq_irq,
+			(void *)mbcs_completion_intr_handler, SA_SHIRQ,
+			"MBCS get intr", (void *)soft)) {
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+
+	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
+	if (sn_irq = NULL) {
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+	soft->put_sn_irq = sn_irq;
+	putDma->intrHostDest = sn_irq->irq_xtalkaddr;
+	putDma->intrVector = sn_irq->irq_irq;
+	if (request_irq(sn_irq->irq_irq,
+			(void *)mbcs_completion_intr_handler, SA_SHIRQ,
+			"MBCS put intr", (void *)soft)) {
+		tiocx_irq_free(soft->put_sn_irq);
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+
+	sn_irq = tiocx_irq_alloc(dev->cx_id.nasid, TIOCX_CORELET, -1, -1, -1);
+	if (sn_irq = NULL) {
+		free_irq(soft->put_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->put_sn_irq);
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+	soft->algo_sn_irq = sn_irq;
+	algo->intrHostDest = sn_irq->irq_xtalkaddr;
+	algo->intrVector = sn_irq->irq_irq;
+	if (request_irq(sn_irq->irq_irq,
+			(void *)mbcs_completion_intr_handler, SA_SHIRQ,
+			"MBCS algo intr", (void *)soft)) {
+		tiocx_irq_free(soft->algo_sn_irq);
+		free_irq(soft->put_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->put_sn_irq);
+		free_irq(soft->get_sn_irq->irq_irq, soft);
+		tiocx_irq_free(soft->get_sn_irq);
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/**
+ * mbcs_intr_dealloc - Remove interrupts.
+ * @dev: device pointer
+ *
+ */
+static void mbcs_intr_dealloc(struct cx_dev *dev)
+{
+	struct mbcs_soft_s *soft;
+
+	soft = dev->soft;
+
+	free_irq(soft->get_sn_irq->irq_irq, soft);
+	tiocx_irq_free(soft->get_sn_irq);
+	free_irq(soft->put_sn_irq->irq_irq, soft);
+	tiocx_irq_free(soft->put_sn_irq);
+	free_irq(soft->algo_sn_irq->irq_irq, soft);
+	tiocx_irq_free(soft->algo_sn_irq);
+}
+
+static int mbcs_hw_init(struct mbcs_soft_s *soft)
+{
+	void *mmr_base = soft->mmr_base;
+	union cm_control_s cm_control;
+	union cm_req_timeout_s cm_req_timeout;
+	uint64_t err_stat;
+
+	cm_req_timeout.cm_req_timeout_reg +	    MBCS_MMR_GET(mmr_base, MBCS_CM_REQ_TOUT);
+
+	cm_req_timeout.time_out = MBCS_CM_CONTROL_REQ_TOUT_MASK;
+	MBCS_MMR_SET(mmr_base, MBCS_CM_REQ_TOUT,
+		     cm_req_timeout.cm_req_timeout_reg);
+
+	mbcs_gscr_pioaddr_set(soft);
+	mbcs_debug_pioaddr_set(soft);
+
+	/* clear errors */
+	err_stat = MBCS_MMR_GET(mmr_base, MBCS_CM_ERR_STAT);
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CLR_ERR_STAT, err_stat);
+	MBCS_MMR_ZERO(mmr_base, MBCS_CM_ERROR_DETAIL1);
+
+	/* enable interrupts */
+	/* turn off 2^23 (INT_EN_PIO_REQ_ADDR_INV) */
+	MBCS_MMR_SET(mmr_base, MBCS_CM_ERR_INT_EN, 0x3ffffff7e00ffUL);
+
+	/* arm status regs and clear engines */
+	cm_control.cm_control_reg = MBCS_MMR_GET(mmr_base, MBCS_CM_CONTROL);
+	cm_control.rearm_stat_regs = 1;
+	cm_control.alg_clr = 1;
+	cm_control.wr_dma_clr = 1;
+	cm_control.rd_dma_clr = 1;
+
+	MBCS_MMR_SET(mmr_base, MBCS_CM_CONTROL, cm_control.cm_control_reg);
+
+	return (0);
+}
+
+static ssize_t show_algo(struct device *dev, char *buf)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct mbcs_soft_s *soft = cx_dev->soft;
+	uint64_t debug0;
+
+	/*
+	 * By convention, the first debug register contains the
+	 * algorithm number and revision.
+	 */
+	debug0 = *(uint64_t *) soft->debug_addr;
+
+	return sprintf(buf, "0x%lx 0x%lx\n",
+		       (debug0 >> 32), (debug0 & 0xffffffff));
+}
+
+static ssize_t store_algo(struct device *dev, const char *buf, size_t count)
+{
+	int n;
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct mbcs_soft_s *soft = cx_dev->soft;
+
+	if (count <= 0)
+		return 0;
+
+	n = simple_strtoul(buf, NULL, 0);
+
+	switch (n) {
+	case 1:
+		algo_start(soft);
+		interruptible_sleep_on(&soft->algo_queue);
+		break;
+	default:
+		break;
+	}
+
+	return count;
+}
+
+DEVICE_ATTR(algo, 0644, show_algo, store_algo);
+
+/**
+ * mbcs_probe - Initialize for device
+ * @dev: device pointer
+ * @device_id: id table pointer
+ *
+ */
+static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
+{
+	struct mbcs_soft_s *soft;
+
+	dev->soft = NULL;
+
+	soft = (struct mbcs_soft_s *)kcalloc(1,
+					     sizeof(struct mbcs_soft_s),
+					     GFP_KERNEL);
+	if (soft = NULL)
+		return -ENOMEM;
+
+	soft->nasid = dev->cx_id.nasid;
+	soft->mmr_base = (void *)tiocx_swin_base(dev->cx_id.nasid);
+	dev->soft = soft;
+
+	init_waitqueue_head(&soft->dmawrite_queue);
+	init_waitqueue_head(&soft->dmaread_queue);
+	init_waitqueue_head(&soft->algo_queue);
+
+	getDma_init(&soft->getDma);
+	putDma_init(&soft->putDma);
+	algo_init(&soft->algo);
+
+	mbcs_hw_init(soft);
+
+	/* Allocate interrupts */
+	mbcs_intr_alloc(dev);
+
+	device_create_file(&dev->dev, &dev_attr_algo);
+
+	return 0;
+}
+
+static int mbcs_remove(struct cx_dev *dev)
+{
+	if (dev->soft) {
+		mbcs_intr_dealloc(dev);
+		kfree(dev->soft);
+	}
+
+	device_remove_file(&dev->dev, &dev_attr_algo);
+
+	return 0;
+}
+
+const struct cx_device_id __devinitdata mbcs_id_table[] = {
+	{
+	 .part_num = MBCS_PART_NUM,
+	 .mfg_num = MBCS_MFG_NUM,
+	 },
+	{
+	 .part_num = MBCS_PART_NUM_ALG0,
+	 .mfg_num = MBCS_MFG_NUM,
+	 },
+	{0, 0}
+};
+
+MODULE_DEVICE_TABLE(cx, mbcs_id_table);
+
+struct cx_drv mbcs_driver = {
+	.name = DEVICE_NAME,
+	.id_table = mbcs_id_table,
+	.probe = mbcs_probe,
+	.remove = mbcs_remove,
+};
+
+static void __exit mbcs_exit(void)
+{
+	int rv;
+
+	rv = unregister_chrdev(mbcs_major, DEVICE_NAME);
+	if (rv < 0)
+		DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv);
+
+	cx_driver_unregister(&mbcs_driver);
+}
+
+static int __init mbcs_init(void)
+{
+	int rv;
+
+	// Put driver into chrdevs[].  Get major number.
+	rv = register_chrdev(mbcs_major, DEVICE_NAME, &mbcs_ops);
+	if (rv < 0) {
+		DBG(KERN_ALERT "mbcs_init: can't get major number. %d\n", rv);
+		return rv;
+	}
+	mbcs_major = rv;
+
+	return cx_driver_register(&mbcs_driver);
+}
+
+module_init(mbcs_init);
+module_exit(mbcs_exit);
+
+MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
+MODULE_DESCRIPTION("Driver for MOATB Core Services");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/mbcs.h b/drivers/char/mbcs.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/mbcs.h	2005-02-28 17:50:10 -06:00
@@ -0,0 +1,549 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#ifndef __MBCS_H__
+#define __MBCS_H__
+
+/*
+ * General macros
+ */
+#define MB	(1024*1024)
+#define MB2	(2*MB)
+#define MB4	(4*MB)
+#define MB6	(6*MB)
+
+/*
+ * Offsets and masks
+ */
+#define MBCS_CM_ID		0x0000	/* Identification */
+#define MBCS_CM_STATUS		0x0008	/* Status */
+#define MBCS_CM_ERROR_DETAIL1	0x0010	/* Error Detail1 */
+#define MBCS_CM_ERROR_DETAIL2	0x0018	/* Error Detail2 */
+#define MBCS_CM_CONTROL		0x0020	/* Control */
+#define MBCS_CM_REQ_TOUT	0x0028	/* Request Time-out */
+#define MBCS_CM_ERR_INT_DEST	0x0038	/* Error Interrupt Destination */
+#define MBCS_CM_TARG_FL		0x0050	/* Target Flush */
+#define MBCS_CM_ERR_STAT	0x0060	/* Error Status */
+#define MBCS_CM_CLR_ERR_STAT	0x0068	/* Clear Error Status */
+#define MBCS_CM_ERR_INT_EN	0x0070	/* Error Interrupt Enable */
+#define MBCS_RD_DMA_SYS_ADDR	0x0100	/* Read DMA System Address */
+#define MBCS_RD_DMA_LOC_ADDR	0x0108	/* Read DMA Local Address */
+#define MBCS_RD_DMA_CTRL	0x0110	/* Read DMA Control */
+#define MBCS_RD_DMA_AMO_DEST	0x0118	/* Read DMA AMO Destination */
+#define MBCS_RD_DMA_INT_DEST	0x0120	/* Read DMA Interrupt Destination */
+#define MBCS_RD_DMA_AUX_STAT	0x0130	/* Read DMA Auxillary Status */
+#define MBCS_WR_DMA_SYS_ADDR	0x0200	/* Write DMA System Address */
+#define MBCS_WR_DMA_LOC_ADDR	0x0208	/* Write DMA Local Address */
+#define MBCS_WR_DMA_CTRL	0x0210	/* Write DMA Control */
+#define MBCS_WR_DMA_AMO_DEST	0x0218	/* Write DMA AMO Destination */
+#define MBCS_WR_DMA_INT_DEST	0x0220	/* Write DMA Interrupt Destination */
+#define MBCS_WR_DMA_AUX_STAT	0x0230	/* Write DMA Auxillary Status */
+#define MBCS_ALG_AMO_DEST	0x0300	/* Algorithm AMO Destination */
+#define MBCS_ALG_INT_DEST	0x0308	/* Algorithm Interrupt Destination */
+#define MBCS_ALG_OFFSETS	0x0310
+#define MBCS_ALG_STEP		0x0318	/* Algorithm Step */
+
+#define MBCS_GSCR_START		0x0000000
+#define MBCS_DEBUG_START	0x0100000
+#define MBCS_RAM0_START		0x0200000
+#define MBCS_RAM1_START		0x0400000
+#define MBCS_RAM2_START		0x0600000
+
+#define MBCS_CM_CONTROL_REQ_TOUT_MASK 0x0000000000ffffffUL
+//#define PIO_BASE_ADDR_BASE_OFFSET_MASK 0x00fffffffff00000UL
+
+#define MBCS_SRAM_SIZE		(1024*1024)
+#define MBCS_CACHELINE_SIZE	128
+
+/*
+ * MMR get's and put's
+ */
+#define MBCS_MMR_ADDR(mmr_base, offset)((uint64_t *)(mmr_base + offset))
+#define MBCS_MMR_SET(mmr_base, offset, value) {			\
+	uint64_t *mbcs_mmr_set_u64p, readback;				\
+	mbcs_mmr_set_u64p = (uint64_t *)(mmr_base + offset);	\
+	*mbcs_mmr_set_u64p = value;					\
+	readback = *mbcs_mmr_set_u64p; \
+}
+#define MBCS_MMR_GET(mmr_base, offset) *(uint64_t *)(mmr_base + offset)
+#define MBCS_MMR_ZERO(mmr_base, offset) MBCS_MMR_SET(mmr_base, offset, 0)
+
+/*
+ * MBCS mmr structures
+ */
+/* *INDENT-OFF* */
+union cm_id_s {
+    uint64_t cm_id_reg;
+    struct {
+		    u_int64_t 	always_one	:	1,	// 0
+				mfg_id		:	11,	// 11:1
+				part_num	:	16,	// 27:12
+				bitstream_rev	:	8,	// 35:28
+						:	28;	// 63:36
+    };
+};
+
+union cm_status_s {
+    uint64_t cm_status_reg;
+    struct {
+	         uint64_t pending_reads		:	 8, 	// 7:0
+	                   pending_writes	:	 8, 	// 15:8
+	                  ice_rsp_credits	:	 8, 	// 23:16
+	                  ice_req_credits	:	 8, 	// 31:24
+	                   cm_req_credits	:	 8, 	// 39:32
+	                   			:	 1, 	// 40
+	               rd_dma_in_progress	:	 1, 	// 41
+	                      rd_dma_done	:	 1, 	// 42
+	                   			:	 1, 	// 43
+	               wr_dma_in_progress	:	 1, 	// 44
+	                      wr_dma_done	:	 1, 	// 45
+	                      alg_waiting	:	 1, 	// 46
+	                 alg_pipe_running	:	 1, 	// 47
+	                         alg_done	:	 1, 	// 48
+	                                 	:	 3, 	// 51:49
+	                 pending_int_reqs	:	 8, 	// 59:52
+	                                 	:	 3, 	// 62:60
+			alg_half_speed_sel	:	 1;	// 63
+    };
+};
+
+union cm_error_detail1_s {
+    uint64_t cm_error_detail1_reg;
+    struct {
+	           uint64_t packet_type		:	 4, 	// 3:0
+	                        source_id	:	 2, 	// 5:4
+	                        data_size	:	 2, 	// 7:6
+	                             tnum	:	 8, 	// 15:8
+	                      byte_enable	:	 8, 	// 23:16
+	                         gfx_cred	:	 8, 	// 31:24
+	                        read_type	:	 2, 	// 33:32
+	                    pio_or_memory	:	 1, 	// 34
+	                    head_cw_error	:	 1, 	// 35
+	                                 	:	12, 	// 47:36
+	                   head_error_bit	:	 1, 	// 48
+	                   data_error_bit	:	 1, 	// 49
+	                                 	:	13, 	// 62:50
+	                            valid	:	 1; 	// 63
+    };
+};
+
+union cm_error_detail2_s {
+    uint64_t cm_error_detail2_reg;
+    struct {
+	               uint64_t address		:	56, 	// 55:0
+	                                 	:	 8; 	// 63:56
+    };
+};
+
+union cm_control_s {
+    uint64_t cm_control_reg;
+    struct {
+	                 uint64_t cm_id		:	 2, 	// 1:0
+	                                 	:	 2, 	// 3:2
+	                        max_trans	:	 5, 	// 8:4
+	                                 	:	 3, 	// 11:9
+	                     address_mode	:	 1, 	// 12
+						:	 7,	// 19:13
+	                     credit_limit	:	 8, 	// 27:20
+	                                 	:	 5, 	// 32:28
+	                  rearm_stat_regs	:	 1, 	// 33
+	                    prescalar_byp	:	 1, 	// 34
+	                    force_gap_war	:	 1, 	// 35
+	                        rd_dma_go	:	 1, 	// 36
+	                        wr_dma_go	:	 1, 	// 37
+	                           alg_go	:	 1, 	// 38
+	                       rd_dma_clr	:	 1, 	// 39
+	                       wr_dma_clr	:	 1, 	// 40
+	                          alg_clr	:	 1, 	// 41
+	              				:	 2, 	// 43:42
+	                    alg_wait_step	:	 1, 	// 44
+	                  alg_done_amo_en	:	 1, 	// 45
+	                  alg_done_int_en	:	 1, 	// 46
+	              				:	 1, 	// 47
+                      alg_sram0_locked          :        1,     // 48
+                      alg_sram1_locked          :        1,     // 49
+                      alg_sram2_locked          :        1,     // 50
+                      alg_done_clr              :        1,     // 51
+                                                :       12;     // 63:52
+    };
+};
+
+union cm_req_timeout_s {
+    uint64_t cm_req_timeout_reg;
+    struct {
+	              uint64_t time_out		:	24, 	// 23:0
+	                                 	:	40; 	// 63:24
+    };
+};
+
+union intr_dest_s {
+    uint64_t intr_dest_reg;
+    struct {
+	               uint64_t address		:	56, 	// 55:0
+	                       int_vector	:	 8; 	// 63:56
+    };
+};
+
+union cm_error_status_s {
+    uint64_t cm_error_status_reg;
+    struct {
+	               uint64_t ecc_sbe		:	 1, 	// 0
+	                          ecc_mbe	:	 1, 	// 1
+	                  unsupported_req	:	 1, 	// 2
+	                   unexpected_rsp	:	 1, 	// 3
+	                       bad_length	:	 1, 	// 4
+	                    bad_datavalid	:	 1, 	// 5
+	                  buffer_overflow	:	 1, 	// 6
+	                  request_timeout	:	 1, 	// 7
+	                                 	:	 8, 	// 15:8
+	               head_inv_data_size	:	 1, 	// 16
+	                  rsp_pactype_inv	:	 1, 	// 17
+	                      head_sb_err	:	 1, 	// 18
+	                     missing_head	:	 1, 	// 19
+	                 head_inv_rd_type	:	 1, 	// 20
+	                 head_cmd_err_bit	:	 1, 	// 21
+	               req_addr_align_inv	:	 1, 	// 22
+	                 pio_req_addr_inv	:	 1, 	// 23
+	              req_range_dsize_inv	:	 1, 	// 24
+	                       early_term	:	 1, 	// 25
+	                       early_tail	:	 1, 	// 26
+	                     missing_tail	:	 1, 	// 27
+	                 data_flit_sb_err	:	 1, 	// 28
+	               cm2hcm_req_cred_of	:	 1, 	// 29
+	               cm2hcm_rsp_cred_of	:	 1, 	// 30
+	                      rx_bad_didn	:	 1, 	// 31
+	                   rd_dma_err_rsp	:	 1, 	// 32
+	                 rd_dma_tnum_tout	:	 1, 	// 33
+	            rd_dma_multi_tnum_tou	:	 1, 	// 34
+	                   wr_dma_err_rsp	:	 1, 	// 35
+	                 wr_dma_tnum_tout	:	 1, 	// 36
+	            wr_dma_multi_tnum_tou	:	 1, 	// 37
+	                alg_data_overflow	:	 1, 	// 38
+	               alg_data_underflow	:	 1, 	// 39
+	             ram0_access_conflict	:	 1, 	// 40
+	             ram1_access_conflict	:	 1, 	// 41
+	             ram2_access_conflict	:	 1, 	// 42
+	                        ram0_perr	:	 1, 	// 43
+	                        ram1_perr	:	 1, 	// 44
+	                        ram2_perr	:	 1, 	// 45
+	                  int_gen_rsp_err	:	 1, 	// 46
+	                int_gen_tnum_tout	:	 1, 	// 47
+	                  rd_dma_prog_err	:	 1, 	// 48
+	                  wr_dma_prog_err	:	 1, 	// 49
+	                                 	:	14; 	// 63:50
+    };
+};
+
+union cm_clr_error_status_s {
+    uint64_t cm_clr_error_status_reg;
+    struct {
+	           uint64_t clr_ecc_sbe		:	 1, 	// 0
+	                      clr_ecc_mbe	:	 1, 	// 1
+	              clr_unsupported_req	:	 1, 	// 2
+	               clr_unexpected_rsp	:	 1, 	// 3
+	                   clr_bad_length	:	 1, 	// 4
+	                clr_bad_datavalid	:	 1, 	// 5
+	              clr_buffer_overflow	:	 1, 	// 6
+	              clr_request_timeout	:	 1, 	// 7
+	                                 	:	 8, 	// 15:8
+	            clr_head_inv_data_siz	:	 1, 	// 16
+	              clr_rsp_pactype_inv	:	 1, 	// 17
+	                  clr_head_sb_err	:	 1, 	// 18
+	                 clr_missing_head	:	 1, 	// 19
+	             clr_head_inv_rd_type	:	 1, 	// 20
+	             clr_head_cmd_err_bit	:	 1, 	// 21
+	            clr_req_addr_align_in	:	 1, 	// 22
+	             clr_pio_req_addr_inv	:	 1, 	// 23
+	            clr_req_range_dsize_i	:	 1, 	// 24
+	                   clr_early_term	:	 1, 	// 25
+	                   clr_early_tail	:	 1, 	// 26
+	                 clr_missing_tail	:	 1, 	// 27
+	             clr_data_flit_sb_err	:	 1, 	// 28
+	            clr_cm2hcm_req_cred_o	:	 1, 	// 29
+	            clr_cm2hcm_rsp_cred_o	:	 1, 	// 30
+	                  clr_rx_bad_didn	:	 1, 	// 31
+	               clr_rd_dma_err_rsp	:	 1, 	// 32
+	             clr_rd_dma_tnum_tout	:	 1, 	// 33
+	            clr_rd_dma_multi_tnum	:	 1, 	// 34
+	               clr_wr_dma_err_rsp	:	 1, 	// 35
+	             clr_wr_dma_tnum_tout	:	 1, 	// 36
+	            clr_wr_dma_multi_tnum	:	 1, 	// 37
+	            clr_alg_data_overflow	:	 1, 	// 38
+	            clr_alg_data_underflo	:	 1, 	// 39
+	            clr_ram0_access_confl	:	 1, 	// 40
+	            clr_ram1_access_confl	:	 1, 	// 41
+	            clr_ram2_access_confl	:	 1, 	// 42
+	                    clr_ram0_perr	:	 1, 	// 43
+	                    clr_ram1_perr	:	 1, 	// 44
+	                    clr_ram2_perr	:	 1, 	// 45
+	              clr_int_gen_rsp_err	:	 1, 	// 46
+	            clr_int_gen_tnum_tout	:	 1, 	// 47
+	              clr_rd_dma_prog_err	:	 1, 	// 48
+	              clr_wr_dma_prog_err	:	 1, 	// 49
+	                                 	:	14; 	// 63:50
+    };
+};
+
+union cm_error_intr_enable_s {
+    uint64_t cm_error_intr_enable_reg;
+    struct {
+	        uint64_t int_en_ecc_sbe		:	 1, 	// 0
+	                   int_en_ecc_mbe	:	 1, 	// 1
+	            int_en_unsupported_re	:	 1, 	// 2
+	            int_en_unexpected_rsp	:	 1, 	// 3
+	                int_en_bad_length	:	 1, 	// 4
+	             int_en_bad_datavalid	:	 1, 	// 5
+	            int_en_buffer_overflo	:	 1, 	// 6
+	            int_en_request_timeou	:	 1, 	// 7
+	                                 	:	 8, 	// 15:8
+	            int_en_head_inv_data_	:	 1, 	// 16
+	            int_en_rsp_pactype_in	:	 1, 	// 17
+	               int_en_head_sb_err	:	 1, 	// 18
+	              int_en_missing_head	:	 1, 	// 19
+	            int_en_head_inv_rd_ty	:	 1, 	// 20
+	            int_en_head_cmd_err_b	:	 1, 	// 21
+	            int_en_req_addr_align	:	 1, 	// 22
+	            int_en_pio_req_addr_i	:	 1, 	// 23
+	            int_en_req_range_dsiz	:	 1, 	// 24
+	                int_en_early_term	:	 1, 	// 25
+	                int_en_early_tail	:	 1, 	// 26
+	              int_en_missing_tail	:	 1, 	// 27
+	            int_en_data_flit_sb_e	:	 1, 	// 28
+	            int_en_cm2hcm_req_cre	:	 1, 	// 29
+	            int_en_cm2hcm_rsp_cre	:	 1, 	// 30
+	               int_en_rx_bad_didn	:	 1, 	// 31
+	            int_en_rd_dma_err_rsp	:	 1, 	// 32
+	            int_en_rd_dma_tnum_to	:	 1, 	// 33
+	            int_en_rd_dma_multi_t	:	 1, 	// 34
+	            int_en_wr_dma_err_rsp	:	 1, 	// 35
+	            int_en_wr_dma_tnum_to	:	 1, 	// 36
+	            int_en_wr_dma_multi_t	:	 1, 	// 37
+	            int_en_alg_data_overf	:	 1, 	// 38
+	            int_en_alg_data_under	:	 1, 	// 39
+	            int_en_ram0_access_co	:	 1, 	// 40
+	            int_en_ram1_access_co	:	 1, 	// 41
+	            int_en_ram2_access_co	:	 1, 	// 42
+	                 int_en_ram0_perr	:	 1, 	// 43
+	                 int_en_ram1_perr	:	 1, 	// 44
+	                 int_en_ram2_perr	:	 1, 	// 45
+	            int_en_int_gen_rsp_er	:	 1, 	// 46
+	            int_en_int_gen_tnum_t	:	 1, 	// 47
+	            int_en_rd_dma_prog_er	:	 1, 	// 48
+	            int_en_wr_dma_prog_er	:	 1, 	// 49
+	                                 	:	14; 	// 63:50
+    };
+};
+
+struct cm_mmr_s {
+    union cm_id_s id;
+    union cm_status_s status;
+    union cm_error_detail1_s err_detail1;
+    union cm_error_detail2_s err_detail2;
+    union cm_control_s control;
+    union cm_req_timeout_s req_timeout;
+    uint64_t reserved1[1];
+    union intr_dest_s int_dest;
+    uint64_t reserved2[2];
+    uint64_t targ_flush;
+    uint64_t reserved3[1];
+    union cm_error_status_s err_status;
+    union cm_clr_error_status_s clr_err_status;
+    union cm_error_intr_enable_s int_enable;
+};
+
+union dma_hostaddr_s {
+    uint64_t dma_hostaddr_reg;
+    struct {
+	          uint64_t dma_sys_addr		:	56, 	// 55:0
+	                                 	:	 8; 	// 63:56
+    };
+};
+
+union dma_localaddr_s {
+    uint64_t dma_localaddr_reg;
+    struct {
+	          uint64_t dma_ram_addr		:	21, 	// 20:0
+	                      dma_ram_sel	:	 2, 	// 22:21
+	                                 	:	41; 	// 63:23
+    };
+};
+
+union dma_control_s {
+    uint64_t dma_control_reg;
+    struct {
+	         uint64_t dma_op_length		:	16, 	// 15:0
+	                    			:	18, 	// 33:16
+	                      done_amo_en	:	 1, 	// 34
+	                      done_int_en	:	 1, 	// 35
+	               				:	 1, 	// 36
+	                        pio_mem_n	:	 1, 	// 37
+	                                 	:	26; 	// 63:38
+    };
+};
+
+union dma_amo_dest_s {
+    uint64_t dma_amo_dest_reg;
+    struct {
+	      uint64_t dma_amo_sys_addr		:	56, 	// 55:0
+	                 dma_amo_mod_type	:	 3, 	// 58:56
+	                                 	:	 5; 	// 63:59
+    };
+};
+
+union rdma_aux_status_s {
+    uint64_t rdma_aux_status_reg;
+    struct {
+	      uint64_t op_num_pacs_left		:	17, 	// 16:0
+	                  			:	 5, 	// 21:17
+	                  lrsp_buff_empty	:	 1, 	// 22
+	                                 	:	17, 	// 39:23
+	                     pending_reqs_left	:	 6, 	// 45:40
+	                                 	:	18; 	// 63:46
+    };
+};
+
+struct rdma_mmr_s {
+    union dma_hostaddr_s host_addr;
+    union dma_localaddr_s local_addr;
+    union dma_control_s control;
+    union dma_amo_dest_s amo_dest;
+    union intr_dest_s intr_dest;
+    union rdma_aux_status_s aux_status;
+};
+
+union wdma_aux_status_s {
+    uint64_t wdma_aux_status_reg;
+    struct {
+	      uint64_t op_num_pacs_left		:	17, 	// 16:0
+	                  			:	 4, 	// 20:17
+	                  lreq_buff_empty	:	 1, 	// 21
+	                                 	:	18, 	// 39:22
+	                     pending_reqs_left	:	 6, 	// 45:40
+	                                 	:	18; 	// 63:46
+    };
+};
+
+struct wdma_mmr_s {
+    union dma_hostaddr_s host_addr;
+    union dma_localaddr_s local_addr;
+    union dma_control_s control;
+    union dma_amo_dest_s amo_dest;
+    union intr_dest_s intr_dest;
+    union wdma_aux_status_s aux_status;
+};
+
+union algo_step_s {
+    uint64_t algo_step_reg;
+    struct {
+	          uint64_t alg_step_cnt		:	16, 	// 15:0
+	                                 	:	48; 	// 63:16
+    };
+};
+
+struct algo_mmr_s {
+    union dma_amo_dest_s amo_dest;
+    union intr_dest_s intr_dest;
+    union {
+        uint64_t algo_offset_reg;
+        struct {
+	    u_int64_t
+	    sram0_offset	:	7,	// 6:0
+	    reserved0		:	1,	// 7
+	    sram1_offset	:	7,	// 14:8
+	    reserved1		:	1,	// 15
+	    sram2_offset	:	7,	// 22:16
+	    reserved2		:	14;	// 63:23
+        };
+    } sram_offset;
+    union algo_step_s step;
+};
+
+struct mbcs_mmr_s {
+    struct cm_mmr_s cm;
+    uint64_t reserved1[17];
+    struct rdma_mmr_s rdDma;
+    uint64_t reserved2[25];
+    struct wdma_mmr_s wrDma;
+    uint64_t reserved3[25];
+    struct algo_mmr_s algo;
+    uint64_t reserved4[156];
+};
+
+/* *INDENT-ON* */
+
+/*
+ * defines
+ */
+#define DEVICE_NAME "mbcs"
+#define MBCS_PART_NUM 0xfff0
+#define MBCS_PART_NUM_ALG0 0xf001
+#define MBCS_MFG_NUM  0x1
+
+struct algo_soft_s {
+	uint64_t amoHostDest;
+	uint64_t amoModType;
+	uint64_t intrHostDest;
+	uint64_t intrVector;
+	uint64_t algoStepCount;
+};
+
+struct getDma_soft_s {
+	uint64_t hostAddr;
+	uint64_t localAddr;
+	uint64_t bytes;
+	uint64_t DoneAmoEnable;
+	uint64_t DoneIntEnable;
+	uint64_t peerIO;
+	uint64_t amoHostDest;
+	uint64_t amoModType;
+	uint64_t intrHostDest;
+	uint64_t intrVector;
+};
+
+struct putDma_soft_s {
+	uint64_t hostAddr;
+	uint64_t localAddr;
+	uint64_t bytes;
+	uint64_t DoneAmoEnable;
+	uint64_t DoneIntEnable;
+	uint64_t peerIO;
+	uint64_t amoHostDest;
+	uint64_t amoModType;
+	uint64_t intrHostDest;
+	uint64_t intrVector;
+};
+
+struct mbcs_soft_s {
+	int major;
+	int nasid;
+	void *mmr_base;
+	wait_queue_head_t dmawrite_queue;
+	wait_queue_head_t dmaread_queue;
+	wait_queue_head_t algo_queue;
+	struct sn_irq_info *get_sn_irq;
+	struct sn_irq_info *put_sn_irq;
+	struct sn_irq_info *algo_sn_irq;
+	struct getDma_soft_s getDma;
+	struct putDma_soft_s putDma;
+	struct algo_soft_s algo;
+	uint64_t gscr_addr;	// pio addr
+	uint64_t ram0_addr;	// pio addr
+	uint64_t ram1_addr;	// pio addr
+	uint64_t ram2_addr;	// pio addr
+	uint64_t debug_addr;	// pio addr
+};
+
+extern int mbcs_open(struct inode *ip, struct file *fp);
+extern ssize_t mbcs_sram_read(struct file *fp, char *buf, size_t len,
+			      loff_t * off);
+extern ssize_t mbcs_sram_write(struct file *fp, const char *buf, size_t len,
+			       loff_t * off);
+extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+
+#endif				// __MBCS_H__
diff -Nru a/drivers/char/tiocx.c b/drivers/char/tiocx.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/tiocx.c	2005-02-28 17:50:10 -06:00
@@ -0,0 +1,555 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Silicon Graphics, Inc.  All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/io.h>
+#include <asm/sn/types.h>
+#include <asm/sn/shubio.h>
+#include <asm/sn/tio.h>
+#include <asm/sn/xtalk/xwidgetdev.h>
+#include <asm/sn/xtalk/hubdev.h>
+#include "tiocx.h"
+
+#define CX_DEV_NONE 0
+#define DEVICE_NAME "tiocx"
+#define WIDGET_ID 0
+#define TIOCX_DEBUG 0
+
+#if TIOCX_DEBUG
+#define DBG(fmt...)    printk(KERN_ALERT fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static int tiocx_match(struct device *dev, struct device_driver *drv);
+static int tiocx_reload(struct cx_dev *);
+static void tio_corelet_reset(nasid_t nasid, int corelet);
+
+static int tiocx_hotplug(struct device *dev, char **envp, int num_envp,
+			 char *buffer, int buffer_size)
+{
+	return -ENODEV;
+}
+
+static void tiocx_bus_release(struct device *dev)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+
+	kfree(cx_dev);
+}
+
+struct bus_type tiocx_bus_type = {
+	.name = "tiocx",
+	.match = tiocx_match,
+	.hotplug = tiocx_hotplug,
+};
+
+static ssize_t show_cxdev_control(struct device *dev, char *buf)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+
+	return sprintf(buf, "0x%x 0x%x 0x%x\n",
+		       cx_dev->cx_id.nasid,
+		       cx_dev->cx_id.part_num, cx_dev->cx_id.mfg_num);
+}
+
+static ssize_t store_cxdev_control(struct device *dev, const char *buf,
+				   size_t count)
+{
+	int n;
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (count <= 0)
+		return 0;
+
+	n = simple_strtoul(buf, NULL, 0);
+
+	switch (n) {
+	case 1:
+		tiocx_reload(cx_dev);
+		break;
+	case 3:
+		tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
+		break;
+	default:
+		break;
+	}
+
+	return count;
+}
+
+DEVICE_ATTR(cxdev_control, 0644, show_cxdev_control, store_cxdev_control);
+
+/**
+ * cx_device_match - Find cx_device in the id table.
+ * @ids: id table from driver
+ * @cx_device: part/mfg id for the device
+ *
+ */
+static const struct cx_device_id *cx_device_match(const struct cx_device_id
+						  *ids,
+						  struct cx_dev *cx_device)
+{
+	/*
+	 * NOTES: We may want to check for CX_ANY_ID too.
+	 *        Do we want to match against nasid too?
+	 *        CX_DEV_NONE = 0, if the driver tries to register for
+	 *        part/mfg = 0 we should return no-match (NULL) here.
+	 */
+	while (ids->part_num && ids->mfg_num) {
+		if (ids->part_num = cx_device->cx_id.part_num &&
+		    ids->mfg_num = cx_device->cx_id.mfg_num)
+			return ids;
+		ids++;
+	}
+
+	return NULL;
+}
+
+/**
+ * cx_device_probe - Look for matching device.
+ *			Call driver probe routine if found.
+ * @cx_driver: driver table (cx_drv struct) from driver
+ * @cx_device: part/mfg id for the device
+ */
+static int cx_device_probe(struct device *dev)
+{
+	const struct cx_device_id *id;
+	struct cx_drv *cx_drv = to_cx_driver(dev->driver);
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	int error = 0;
+
+	if (!cx_dev->driver && cx_drv->probe) {
+		id = cx_device_match(cx_drv->id_table, cx_dev);
+		if (id) {
+			if ((error = cx_drv->probe(cx_dev, id)) < 0)
+				return error;
+			else
+				cx_dev->driver = cx_drv;
+		}
+	}
+
+	return error;
+}
+
+/**
+ * cx_driver_remove - Remove driver from device struct.
+ * @dev: device
+ */
+static int cx_driver_remove(struct device *dev)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct cx_drv *cx_drv = cx_dev->driver;
+	if (cx_drv->remove)
+		cx_drv->remove(cx_dev);
+	cx_dev->driver = NULL;
+	return 0;
+}
+
+/**
+ * cx_driver_register - Register the driver.
+ * @cx_driver: driver table (cx_drv struct) from driver
+ * 
+ * Called from the driver init routine to register a driver.
+ * The cx_drv struct contains the driver name, a pointer to
+ * a table of part/mfg numbers and a pointer to the driver's
+ * probe/attach routine.
+ */
+int cx_driver_register(struct cx_drv *cx_driver)
+{
+	cx_driver->driver.name = cx_driver->name;
+	cx_driver->driver.bus = &tiocx_bus_type;
+	cx_driver->driver.probe = cx_device_probe;
+	cx_driver->driver.remove = cx_driver_remove;
+
+	return driver_register(&cx_driver->driver);
+}
+
+/**
+ * cx_driver_unregister - Unregister the driver.
+ * @cx_driver: driver table (cx_drv struct) from driver
+ */
+int cx_driver_unregister(struct cx_drv *cx_driver)
+{
+	driver_unregister(&cx_driver->driver);
+	return 0;
+}
+
+/**
+ * cx_device_register - Register a device.
+ * @nasid: device's nasid
+ * @part_num: device's part number
+ * @mfg_num: device's manufacturer number
+ * @hubdev: hub info associated with this device
+ *
+ */
+int
+cx_device_register(nasid_t nasid, int part_num, int mfg_num,
+		   struct hubdev_info *hubdev)
+{
+	struct cx_dev *cx_dev;
+
+	cx_dev = kcalloc(1, sizeof(struct cx_dev), GFP_KERNEL);
+	DBG("cx_dev= 0x%p\n", cx_dev);
+	if (cx_dev = NULL)
+		return -ENOMEM;
+
+	cx_dev->cx_id.part_num = part_num;
+	cx_dev->cx_id.mfg_num = mfg_num;
+	cx_dev->cx_id.nasid = nasid;
+	cx_dev->hubdev = hubdev;
+
+	cx_dev->dev.parent = NULL;
+	cx_dev->dev.bus = &tiocx_bus_type;
+	cx_dev->dev.release = tiocx_bus_release;
+	snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x",
+		 cx_dev->cx_id.nasid, cx_dev->cx_id.part_num);
+	device_register(&cx_dev->dev);
+	get_device(&cx_dev->dev);
+
+	device_create_file(&cx_dev->dev, &dev_attr_cxdev_control);
+
+	return 0;
+}
+
+/**
+ * cx_device_unregister - Unregister a device.
+ * @cx_dev: part/mfg id for the device
+ */
+int cx_device_unregister(struct cx_dev *cx_dev)
+{
+	put_device(&cx_dev->dev);
+	device_unregister(&cx_dev->dev);
+	return 0;
+}
+
+/**
+ * cx_device_reload - Reload the device.
+ * @nasid: device's nasid
+ * @part_num: device's part number
+ * @mfg_num: device's manufacturer number
+ *
+ * Remove the device associated with 'nasid' from device list and then
+ * call device-register with the given part/mfg numbers.
+ */
+static int cx_device_reload(struct cx_dev *cx_dev)
+{
+	device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control);
+	cx_device_unregister(cx_dev);
+	return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
+				  cx_dev->cx_id.mfg_num, cx_dev->hubdev);
+}
+
+static inline uint64_t tiocx_intr_alloc(nasid_t nasid, int widget,
+					u64 sn_irq_info,
+					int req_irq, nasid_t req_nasid,
+					int req_slice)
+{
+	struct ia64_sal_retval rv;
+	rv.status = 0;
+	rv.v0 = 0;
+
+	ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
+				SAL_INTR_ALLOC, nasid,
+				widget, sn_irq_info, req_irq,
+				req_nasid, req_slice);
+	return rv.status;
+}
+
+static inline void tiocx_intr_free(nasid_t nasid, int widget,
+				   struct sn_irq_info *sn_irq_info)
+{
+	struct ia64_sal_retval rv;
+	rv.status = 0;
+	rv.v0 = 0;
+
+	ia64_sal_oemcall_nolock(&rv, SN_SAL_IOIF_INTERRUPT,
+				SAL_INTR_FREE, nasid,
+				widget, sn_irq_info->irq_irq,
+				sn_irq_info->irq_cookie, 0, 0);
+}
+
+struct sn_irq_info *tiocx_irq_alloc(nasid_t nasid, int widget, int irq,
+				    nasid_t req_nasid, int slice)
+{
+	struct sn_irq_info *sn_irq_info;
+	int status;
+	int sn_irq_size = sizeof(struct sn_irq_info);
+
+	if ((nasid & 1) = 0)
+		return NULL;
+
+	sn_irq_info = kmalloc(sn_irq_size, GFP_KERNEL);
+	if (sn_irq_info = NULL)
+		return NULL;
+
+	memset(sn_irq_info, 0x0, sn_irq_size);
+
+	status = tiocx_intr_alloc(nasid, widget, __pa(sn_irq_info), irq,
+				  req_nasid, slice);
+	if (status) {
+		kfree(sn_irq_info);
+		return NULL;
+	} else {
+		return sn_irq_info;
+	}
+}
+
+void tiocx_irq_free(struct sn_irq_info *sn_irq_info)
+{
+	uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
+	nasid_t nasid = NASID_GET(bridge);
+	int widget;
+
+	if ((nasid & 1) = 0)
+		return;
+
+	widget = TIO_SWIN_WIDGETNUM(bridge);
+
+	tiocx_intr_free(nasid, widget, sn_irq_info);
+
+	kfree(sn_irq_info);
+}
+
+uint64_t
+tiocx_dma_addr(uint64_t addr)
+{
+	return PHYS_TO_TIODMA(addr);
+}
+
+uint64_t
+tiocx_swin_base(int nasid)
+{
+	return TIO_SWIN_BASE(nasid, TIOCX_CORELET);
+}
+
+EXPORT_SYMBOL(cx_driver_register);
+EXPORT_SYMBOL(cx_driver_unregister);
+EXPORT_SYMBOL(cx_device_register);
+EXPORT_SYMBOL(cx_device_unregister);
+EXPORT_SYMBOL(tiocx_irq_alloc);
+EXPORT_SYMBOL(tiocx_irq_free);
+EXPORT_SYMBOL(tiocx_bus_type);
+EXPORT_SYMBOL(tiocx_dma_addr);
+EXPORT_SYMBOL(tiocx_swin_base);
+
+/**
+ * tiocx_match - Try to match driver id list with device.
+ * @dev: device pointer
+ * @drv: driver pointer
+ *
+ * Returns 1 if match, 0 otherwise.
+ */
+static int tiocx_match(struct device *dev, struct device_driver *drv)
+{
+	struct cx_dev *cx_dev = to_cx_dev(dev);
+	struct cx_drv *cx_drv = to_cx_driver(drv);
+	const struct cx_device_id *ids = cx_drv->id_table;
+
+	if (!ids)
+		return 0;
+
+	while (ids->part_num) {
+		if (ids->part_num = cx_dev->cx_id.part_num)
+			return 1;
+		ids++;
+	}
+	return 0;
+
+}
+
+static uint64_t tiocx_get_hubdev_info(u64 handle, u64 address)
+{
+
+	struct ia64_sal_retval ret_stuff;
+	ret_stuff.status = 0;
+	ret_stuff.v0 = 0;
+
+	ia64_sal_oemcall_nolock(&ret_stuff,
+				SN_SAL_IOIF_GET_HUBDEV_INFO,
+				handle, address, 0, 0, 0, 0, 0);
+	return ret_stuff.v0;
+}
+
+static void tio_conveyor_set(nasid_t nasid, int enable_flag)
+{
+	u_int64_t ice_frz;
+	u_int64_t disable_cb = (1ull << 61);
+
+	if (!(nasid & 1))
+		return;
+
+	ice_frz = REMOTE_HUB_L(nasid, TIO_ICE_FRZ_CFG);
+	if (enable_flag) {
+		if (!(ice_frz & disable_cb))	/* already enabled */
+			return;
+		ice_frz &= ~disable_cb;
+	} else {
+		if (ice_frz & disable_cb)	/* already disabled */
+			return;
+		ice_frz |= disable_cb;
+	}
+	DBG(KERN_ALERT "TIO_ICE_FRZ_CFG= 0x%lx\n", ice_frz);
+	REMOTE_HUB_S(nasid, TIO_ICE_FRZ_CFG, ice_frz);
+}
+
+#define tio_conveyor_enable(nasid) tio_conveyor_set(nasid, 1)
+#define tio_conveyor_disable(nasid) tio_conveyor_set(nasid, 0)
+
+static void tio_corelet_reset(nasid_t nasid, int corelet)
+{
+	if (!(nasid & 1))
+		return;
+
+	REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 1 << corelet);
+	udelay(2000);
+	REMOTE_HUB_S(nasid, TIO_ICE_PMI_TX_CFG, 0);
+	udelay(2000);
+}
+
+static int fpga_attached(nasid_t nasid)
+{
+	u_int64_t cx_credits;
+
+	cx_credits = REMOTE_HUB_L(nasid, TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3);
+	cx_credits &= TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK;
+	DBG("cx_credits= 0x%lx\n", cx_credits);
+
+	return (cx_credits = 0xf) ? 1 : 0;
+}
+
+static int tiocx_reload(struct cx_dev *cx_dev)
+{
+	int part_num = CX_DEV_NONE;
+	int mfg_num = CX_DEV_NONE;
+	nasid_t nasid = cx_dev->cx_id.nasid;
+
+	if (fpga_attached(nasid)) {
+		u_int64_t cx_id;
+
+		cx_id +		    *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
+					  WIDGET_ID);
+		part_num = XWIDGET_PART_NUM(cx_id);
+		mfg_num = XWIDGET_MFG_NUM(cx_id);
+		DBG("part= 0x%x, mfg= 0x%x\n", part_num, mfg_num);
+		/* just ignore it if it's a CE */
+		if (part_num = TIO_CE_ASIC_PARTNUM)
+			return 0;
+	}
+
+	cx_dev->cx_id.part_num = part_num;
+	cx_dev->cx_id.mfg_num = mfg_num;
+
+	/*
+	 * Delete old device and register the new one.  It's ok if
+	 * part_num/mfg_num = CX_DEV_NONE.  We want to register
+	 * devices in the table even if a bitstream isn't loaded.
+	 * That allows use to see that a bitstream isn't loaded via
+	 * TIOCX_IOCTL_DEV_LIST.
+	 */
+	return cx_device_reload(cx_dev);
+}
+
+static int __init tiocx_init(void)
+{
+	cnodeid_t cnodeid;
+	int found_tiocx_device = 0;
+
+	bus_register(&tiocx_bus_type);
+
+	for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
+		nasid_t nasid;
+
+		if ((nasid = cnodeid_to_nasid(cnodeid)) < 0)
+			break;	/* No more nasids .. bail out of loop */
+
+		if (nasid & 0x1) {	/* TIO's are always odd */
+			struct hubdev_info *hubdev;
+			uint64_t status;
+			struct xwidget_info *widgetp;
+
+			DBG("Found TIO at nasid 0x%x\n", nasid);
+
+			hubdev +			    (struct hubdev_info *)(NODEPDA(cnodeid)->pdinfo);
+			status +			    tiocx_get_hubdev_info(nasid,
+						  (uint64_t) __pa(hubdev));
+			if (status)
+				continue;
+
+			widgetp = &hubdev->hdi_xwidget_info[TIOCX_CORELET];
+
+			/* The CE hangs off of the CX port but is not an FPGA */
+			if (widgetp->xwi_hwid.part_num = TIO_CE_ASIC_PARTNUM)
+				continue;
+
+			tio_corelet_reset(nasid, TIOCX_CORELET);
+			tio_conveyor_enable(nasid);
+
+			if (cx_device_register
+			    (nasid, widgetp->xwi_hwid.part_num,
+			     widgetp->xwi_hwid.mfg_num, hubdev) < 0)
+				return -ENXIO;
+			else
+				found_tiocx_device++;
+		}
+	}
+
+	/* It's ok if we find zero devices. */
+	DBG("found_tiocx_device= %d\n", found_tiocx_device);
+
+	return 0;
+}
+
+static void __exit tiocx_exit(void)
+{
+	struct device *dev;
+	struct device *tdev;
+
+	DBG("tiocx_exit\n");
+
+	/*
+	 * Unregister devices.
+	 */
+	list_for_each_entry_safe(dev, tdev, &tiocx_bus_type.devices.list,
+				 bus_list) {
+		if (dev) {
+			struct cx_dev *cx_dev = to_cx_dev(dev);
+			device_remove_file(dev, &dev_attr_cxdev_control);
+			cx_device_unregister(cx_dev);
+		}
+	}
+
+	bus_unregister(&tiocx_bus_type);
+}
+
+module_init(tiocx_init);
+module_exit(tiocx_exit);
+
+/************************************************************************
+ * Module licensing and description
+ ************************************************************************/
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bruce Losure <blosure@sgi.com>");
+MODULE_DESCRIPTION("TIOCX module");
+MODULE_SUPPORTED_DEVICE(DEVICE_NAME);
diff -Nru a/drivers/char/tiocx.h b/drivers/char/tiocx.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/char/tiocx.h	2005-02-28 17:50:10 -06:00
@@ -0,0 +1,71 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 2005 Silicon Graphics, Inc. All rights reserved.
+ */
+
+#ifndef _ASM_IA64_SN_TIO_TIOCX_H
+#define _ASM_IA64_SN_TIO_TIOCX_H
+
+#ifdef __KERNEL__
+
+struct cx_id_s {
+	unsigned int part_num;
+	unsigned int mfg_num;
+	int nasid;
+};
+
+struct cx_dev {
+	struct cx_id_s cx_id;
+	void *soft;			/* driver specific */
+	struct hubdev_info *hubdev;
+	struct device dev;
+	struct cx_drv *driver;
+};
+
+struct cx_device_id {
+	unsigned int part_num;
+	unsigned int mfg_num;
+};
+
+struct cx_drv {
+	char *name;
+	const struct cx_device_id *id_table;
+	struct device_driver driver;
+	int (*probe) (struct cx_dev * dev, const struct cx_device_id * id);
+	int (*remove) (struct cx_dev * dev);
+};
+
+/* create DMA address by stripping AS bits */
+#define TIOCX_DMA_ADDR(a) (uint64_t)((uint64_t)(a) & 0xffffcfffffffffUL)
+
+#define TIOCX_TO_TIOCX_DMA_ADDR(a) (uint64_t)(((uint64_t)(a) & 0xfffffffff) |  \
+                                  ((((uint64_t)(a)) & 0xffffc000000000UL) <<2))
+
+#define TIO_CE_ASIC_PARTNUM 0xce00
+#define TIOCX_CORELET 3
+
+/* These are taken from tio_mmr_as.h */
+#define TIO_ICE_FRZ_CFG               TIO_MMR_ADDR_MOD(0x00000000b0008100UL)
+#define TIO_ICE_PMI_TX_CFG            TIO_MMR_ADDR_MOD(0x00000000b000b100UL)
+#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3 TIO_MMR_ADDR_MOD(0x00000000b000be18UL)
+#define TIO_ICE_PMI_TX_DYN_CREDIT_STAT_CB3_CREDIT_CNT_MASK 0x000000000000000fUL
+
+#define to_cx_dev(n) container_of(n, struct cx_dev, dev)
+#define to_cx_driver(drv) container_of(drv, struct cx_drv, driver)
+
+extern struct sn_irq_info *tiocx_irq_alloc(nasid_t, int, int, nasid_t, int);
+extern void tiocx_irq_free(struct sn_irq_info *);
+extern int cx_device_unregister(struct cx_dev *);
+extern int cx_device_register(nasid_t, int, int, struct hubdev_info *);
+extern int cx_driver_unregister(struct cx_drv *);
+extern int cx_driver_register(struct cx_drv *);
+extern uint64_t tiocx_dma_addr(uint64_t addr);
+extern uint64_t tiocx_swin_base(int nasid);
+extern void tiocx_mmr_store(int nasid, uint64_t offset, uint64_t value);
+extern uint64_t tiocx_mmr_load(int nasid, uint64_t offset);
+
+#endif				//  __KERNEL__
+#endif				// _ASM_IA64_SN_TIO_TIOCX__
diff -Nru a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h
--- a/include/asm-ia64/sn/addrs.h	2005-02-28 17:50:10 -06:00
+++ b/include/asm-ia64/sn/addrs.h	2005-02-28 17:50:10 -06:00
@@ -167,7 +167,9 @@
 #define TIO_BWIN_SIZE_BITS		30	/* big window size: 1G */
 #define NODE_SWIN_BASE(n, w)		((w = 0) ? NODE_BWIN_BASE((n), SWIN0_BIGWIN) \
 		: RAW_NODE_SWIN_BASE(n, w))
+#define TIO_SWIN_BASE(n, w) 		(TIO_IO_BASE(n) + ((u64) (w) << TIO_SWIN_SIZE_BITS))
 #define NODE_IO_BASE(n)			(GLOBAL_MMR_SPACE | NASID_SPACE(n))
+#define TIO_IO_BASE(n)                  (UNCACHED | NASID_SPACE(n))
 #define BWIN_SIZE			(1UL << BWIN_SIZE_BITS)
 #define NODE_BWIN_BASE0(n)		(NODE_IO_BASE(n) + BWIN_SIZE)
 #define NODE_BWIN_BASE(n, w)		(NODE_BWIN_BASE0(n) + ((u64) (w) << BWIN_SIZE_BITS))

-- 
Bruce Losure                            internet: blosure@sgi.com
SGI                                     phone:    +1 651 683-7263
2750 Blue Water Rd			vnet:	  233-7263
Eagan, MN, USA 55121

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip
  2005-02-28 23:58 [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Bruce Losure
@ 2005-03-02  4:47 ` Christoph Hellwig
  2005-03-02 17:21 ` Jesse Barnes
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2005-03-02  4:47 UTC (permalink / raw)
  To: linux-ia64

(care to split this into a two-patch series for the next submission,
one for tiocx, one for mbcs?)

> +obj-$(CONFIG_SGI_TIOCX)		+= tiocx.o

this one should really be in arch/ia64/sn/

> +#endif
> +int mbcs_major = 0;
> +
> +extern struct bus_type tiocx_bus_type;

externs in .c files are a big no-go in Linux.  But you
shouldn't need this variable anyway.

> +static void getDma_init(struct getDma_soft_s *pGetDma)

please avoid oddly-Caps names and _s prefix for structures,
should more look like

static void mbcs_getdma_init(struct getdma *gd)

> +{
> +	/* setup engine parameters */
> +	pGetDma->hostAddr = 0;
> +	pGetDma->localAddr = 0;
> +	pGetDma->bytes = 0;
> +	pGetDma->DoneAmoEnable = 0;
> +	pGetDma->DoneIntEnable = 1;
> +	pGetDma->peerIO = 0;
> +	pGetDma->amoHostDest = 0;
> +	pGetDma->amoModType = 0;
> +	pGetDma->intrHostDest = 0;
> +	pGetDma->intrVector = 0;

why not memset the whole structure?

> +static ssize_t
> +do_mbcs_sram_dmaread(struct mbcs_soft_s *soft, uint64_t hostAddr,
> +		     size_t len, loff_t * off)
> +{
> +	int rv = 0;
> +
> +	soft->getDma.hostAddr = hostAddr;
> +	soft->getDma.localAddr = *off;
> +	soft->getDma.bytes = len;
> +
> +	if (getDma_start(soft) < 0) {
> +		DBG(KERN_ALERT "mbcs_strategy: getDma_start failed\n");
> +		return -EAGAIN;
> +	}
> +
> +	interruptible_sleep_on(&soft->dmaread_queue);

never use sleep_on or its variants.  Use wait_event instead with a proper
condition to wait for.  (Also in various other places in the driver)

> +{
> +	struct mbcs_callback_arg cba;
> +
> +	if (ip = NULL || fp = NULL)
> +		return -EINVAL;

can't ever happen.

> 
> +
> +	cba.minor = iminor(ip);
> +
> +	cba.cx_dev = NULL;
> +	bus_for_each_dev(&tiocx_bus_type, NULL, &cba, mbcs_find_device);

urgg, no.  Please keep a local doubly-linked list of devices you
got ->porbe called for and search that one.

> +static int mbcs_probe(struct cx_dev *dev, const struct cx_device_id *id)
> +{
> +	struct mbcs_soft_s *soft;
> +
> +	dev->soft = NULL;
> +
> +	soft = (struct mbcs_soft_s *)kcalloc(1,
> +					     sizeof(struct mbcs_soft_s),
> +					     GFP_KERNEL);

no need to cast the kcalloc return value


the whole mbcs driver looks rather odd, what is it trying to do?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip
  2005-02-28 23:58 [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Bruce Losure
  2005-03-02  4:47 ` Christoph Hellwig
@ 2005-03-02 17:21 ` Jesse Barnes
  2005-03-02 19:36 ` [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX Bruce Losure
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Jesse Barnes @ 2005-03-02 17:21 UTC (permalink / raw)
  To: linux-ia64

On Tuesday, March 1, 2005 8:47 pm, Christoph Hellwig wrote:
> (care to split this into a two-patch series for the next submission,
> one for tiocx, one for mbcs?)
>
> > +obj-$(CONFIG_SGI_TIOCX)  += tiocx.o
>
> this one should really be in arch/ia64/sn/

Even though it's a char driver?  I told him to put it in drivers/char to make 
API change sweeps a bit easier...  Fine with me if it ends up in arch/ia64/sn 
though.

Jesse

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX
  2005-02-28 23:58 [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Bruce Losure
  2005-03-02  4:47 ` Christoph Hellwig
  2005-03-02 17:21 ` Jesse Barnes
@ 2005-03-02 19:36 ` Bruce Losure
  2005-03-02 19:42 ` Rich Altmaier
  2005-03-02 21:40 ` [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Christoph Hellwig
  4 siblings, 0 replies; 6+ messages in thread
From: Bruce Losure @ 2005-03-02 19:36 UTC (permalink / raw)
  To: linux-ia64


I've made all the changes you suggested and hope to resubmit today.

>
> the whole mbcs driver looks rather odd, what is it trying to do?
>

It's for current and upcoming FPGA based h/w.   Broadly speaking, the
FPGA contains two components a 'core services' component and a customer
component.    The core services are largely just dma engines and logic
to interact with the customer portion.   That's what the driver is
dealing with.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX
  2005-02-28 23:58 [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Bruce Losure
                   ` (2 preceding siblings ...)
  2005-03-02 19:36 ` [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX Bruce Losure
@ 2005-03-02 19:42 ` Rich Altmaier
  2005-03-02 21:40 ` [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Christoph Hellwig
  4 siblings, 0 replies; 6+ messages in thread
From: Rich Altmaier @ 2005-03-02 19:42 UTC (permalink / raw)
  To: linux-ia64

FYI,
  Using FPGAs in computing - Reconfigurable Application-specific Computing.

   http://www.sgi.com/pdfs/3721.pdf

Thanks, Rich


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip
  2005-02-28 23:58 [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Bruce Losure
                   ` (3 preceding siblings ...)
  2005-03-02 19:42 ` Rich Altmaier
@ 2005-03-02 21:40 ` Christoph Hellwig
  4 siblings, 0 replies; 6+ messages in thread
From: Christoph Hellwig @ 2005-03-02 21:40 UTC (permalink / raw)
  To: linux-ia64

On Wed, Mar 02, 2005 at 09:21:43AM -0800, Jesse Barnes wrote:
> On Tuesday, March 1, 2005 8:47 pm, Christoph Hellwig wrote:
> > (care to split this into a two-patch series for the next submission,
> > one for tiocx, one for mbcs?)
> >
> > > +obj-$(CONFIG_SGI_TIOCX)  += tiocx.o
> >
> > this one should really be in arch/ia64/sn/
> 
> Even though it's a char driver?  I told him to put it in drivers/char to make 
> API change sweeps a bit easier...  Fine with me if it ends up in arch/ia64/sn 
> though.

The tiocx driver is a bus driver for the CX bus, mbcs is the char driver.


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2005-03-02 21:40 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-28 23:58 [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Bruce Losure
2005-03-02  4:47 ` Christoph Hellwig
2005-03-02 17:21 ` Jesse Barnes
2005-03-02 19:36 ` [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX Bruce Losure
2005-03-02 19:42 ` Rich Altmaier
2005-03-02 21:40 ` [PATCH 2.6.11-rc3 1/1] altix: Device driver support for the CX port of SGI's TIO chip Christoph Hellwig

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.