[parisc-linux-cvs] Re: DIFF 2.4.18-pa14

Grant Grundler grundler@dsl2.external.hp.com
Fri, 05 Apr 2002 01:08:58 -0700


Grant Grundler wrote:
> Log message:
> 2.4.18-pa14 PA8700/SBA bug fix (no, we don't support PA8700 yet)
> o add bug fix for older revs of PA8700 on SBA systems
> o made IO PDIR allocation smarter:  iopdir_size ~= phys_hostmem/num_iommu
> o cleanup 64-bit reads/debug info
> o disabled /proc/bus/runway/bitmap since "cat"ing that file will crash
> the system (exceeds 4k of output).

Kills some of the TODO Items I had.
Still outstanding:
o try using (maybe only PAT) PDC for PCI config cycles
o cleanup J6000 hack to use "old" PCI config access method
o fix warning about "Ignoring enabled ELMMIO BASE" so it only shows
  up if the SBA is directing addresses down that rope.


Index: Makefile
===================================================================
RCS file: /var/cvs/linux/Makefile,v
retrieving revision 1.284
diff -u -p -r1.284 Makefile
--- Makefile	2002/04/03 03:11:01	1.284
+++ Makefile	2002/04/05 07:43:09
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 18
-EXTRAVERSION = -pa13
+EXTRAVERSION = -pa14
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: arch/parisc/kernel/cache.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/cache.c,v
retrieving revision 1.20
diff -u -p -r1.20 cache.c
--- arch/parisc/kernel/cache.c	2001/11/29 20:53:44	1.20
+++ arch/parisc/kernel/cache.c	2002/04/05 07:43:10
@@ -186,13 +186,11 @@ cache_init(void)
 	}
 #endif
 
-	if (pdc_model_capabilities(&capabilities) == 0) {
-		if ((capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) {
-			printk(KERN_WARNING "Only equivalent aliasing supported\n");
+	if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) == PDC_MODEL_NVA_UNSUPPORTED) {
+		printk(KERN_WARNING "Only equivalent aliasing supported\n");
 #ifndef CONFIG_SMP
-			panic("SMP kernel required to avoid non-equivalent aliasing");
+		panic("SMP kernel required to avoid non-equivalent aliasing");
 #endif
-		}
 	}
 }
 
Index: arch/parisc/kernel/drivers.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/drivers.c,v
retrieving revision 1.45
diff -u -p -r1.45 drivers.c
--- arch/parisc/kernel/drivers.c	2002/02/28 07:11:20	1.45
+++ arch/parisc/kernel/drivers.c	2002/04/05 07:43:10
@@ -142,6 +142,26 @@ int register_parisc_driver(struct parisc
 	return 0;
 }
 
+/**
+ * count_parisc_driver - count # of devices this driver would match
+ * @driver: the PA-RISC driver to try
+ *
+ * Use by IOMMU support to "guess" the right size IOPdir.
+ * Formula is something like memsize/(num_iommu * entry_size).
+ */
+int count_parisc_driver(struct parisc_driver *driver)
+{
+	struct parisc_device *device;
+	int cnt = 0;
+
+	for_each_padev(device) {
+		if (match_device(driver, device))
+			cnt++;
+	}
+
+	return cnt;
+}
+
 
 
 /**
Index: arch/parisc/kernel/lba_pci.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/lba_pci.c,v
retrieving revision 1.49
diff -u -p -r1.49 lba_pci.c
--- arch/parisc/kernel/lba_pci.c	2002/03/07 21:13:11	1.49
+++ arch/parisc/kernel/lba_pci.c	2002/04/05 07:43:12
@@ -63,12 +63,6 @@
 
 #undef FBB_SUPPORT	/* Fast Back-Back xfers - NOT READY YET */
 
-#ifdef __LP64__
-/* workarounds for brokeness in PAT PDC
-** Hopefully these can/will go away as new PDC revs become available.
-*/
-#define PDC_PAT_BUG
-#endif
 
 #ifdef DEBUG_LBA
 #define DBG(x...)	printk(x)
@@ -240,9 +234,7 @@ static u32 lba_t32;
 #define READ_REG8(addr)  readb(addr)
 #define READ_REG16(addr) readw(addr)
 #define READ_REG32(addr) readl(addr)
-#if BITS_PER_LONG > 32
 #define READ_REG64(addr) readq(addr)
-#endif
 #define WRITE_REG8(value, addr)  writeb(value, addr)
 #define WRITE_REG16(value, addr) writew(value, addr)
 #define WRITE_REG32(value, addr) writel(value, addr)
@@ -1208,7 +1200,7 @@ lba_legacy_resources(struct parisc_devic
 		r->start &= ~1;
 		r->end    = r->start;
 		r->end   += ~READ_REG32(pa_dev->hpa + LBA_ELMMIO_MASK);
-		printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0x  SIZE 0x%x\n",
+		printk(KERN_DEBUG "WARNING: Ignoring enabled ELMMIO BASE 0x%0lx  SIZE 0x%lx\n",
 			r->start,
 			r->end + 1);
 
@@ -1243,11 +1235,9 @@ static int __init
 lba_hw_init(struct lba_device *d)
 {
 	u32 stat;
-#ifdef PDC_PAT_BUG
-	u32 bus_reset;
-#endif
+	u32 bus_reset;	/* PDC_PAT_BUG */
 
-#ifdef DEBUG_LBA_PAT
+#if 1
 	printk(KERN_DEBUG "LBA %p  STAT_CTL %Lx  ERROR_CFG %Lx  STATUS %Lx DMA_CTL %Lx\n",
 		d->hba.base_addr,
 		READ_REG64(d->hba.base_addr + LBA_STAT_CTL),
@@ -1259,23 +1249,29 @@ lba_hw_init(struct lba_device *d)
 		READ_REG64(d->hba.base_addr + LBA_ARB_PRI),
 		READ_REG64(d->hba.base_addr + LBA_ARB_MODE),
 		READ_REG64(d->hba.base_addr + LBA_ARB_MTLT) );
+	printk(KERN_DEBUG "	HINT cfg 0x%Lx\n",
+		READ_REG64(d->hba.base_addr + LBA_HINT_CFG));
+	printk(KERN_DEBUG "	HINT reg ");
+	{ int i;
+	for (i=LBA_HINT_BASE; i< (14*8 + LBA_HINT_BASE); i+=8)
+		printk(" %Lx", READ_REG64(d->hba.base_addr + i));
+	}
+	printk("\n");
 #endif	/* DEBUG_LBA_PAT */
 
 #ifdef __LP64__
 #warning FIXME add support for PDC_PAT_IO "Get slot status" - OLAR support
 #endif
 
-#ifdef PDC_PAT_BUG
-	/* Bug exhibited with PDC rev 40.48  on L2000 */
+	/* PDC_PAT_BUG: exhibited in rev 40.48  on L2000 */
 	bus_reset = READ_REG32(d->hba.base_addr + LBA_STAT_CTL + 4) & 1;
 	if (bus_reset) {
-		BUG();
+		printk(KERN_DEBUG "NOTICE: PCI bus reset still asserted! (clearing)\n");
 	}
-#endif
 
 	stat = READ_REG32(d->hba.base_addr + LBA_ERROR_CONFIG);
 	if (stat & LBA_SMART_MODE) {
-		BUG();	/* should be off be default */
+		printk(KERN_DEBUG "NOTICE: LBA in SMART mode! (cleared)\n");
 		stat &= ~LBA_SMART_MODE;
 		WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
 	}
@@ -1284,7 +1280,6 @@ lba_hw_init(struct lba_device *d)
         stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
 	WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
 
-#ifdef PDC_PAT_BUG
 	/*
 	** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
 	** if it's not already set. If we just cleared the PCI Bus Reset
@@ -1292,11 +1287,10 @@ lba_hw_init(struct lba_device *d)
 	*/
 	if (bus_reset)
 		mdelay(pci_post_reset_delay);
-#endif
 
 	if (0 == READ_REG32(d->hba.base_addr + LBA_ARB_MASK)) {
 		/*
-		** Bug exhibited with PDC rev 40.48 on L2000.
+		** PDC_PAT_BUG: PDC rev 40.48 on L2000.
 		** B2000/C3600/J6000 also have this problem?
 		** 
 		** Elroys with hot pluggable slots don't get configured
@@ -1304,7 +1298,7 @@ lba_hw_init(struct lba_device *d)
 		** and we can't master transactions on the bus if it's
 		** not at least one. 0x3 enables elroy and first slot.
 		*/
-		BUG();
+		printk(KERN_DEBUG "NOTICE: Enabling PCI Arbitration\n");
 		WRITE_REG32(0x3, d->hba.base_addr + LBA_ARB_MASK);
 	}
 
Index: arch/parisc/kernel/processor.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/processor.c,v
retrieving revision 1.9
diff -u -p -r1.9 processor.c
--- arch/parisc/kernel/processor.c	2001/11/29 20:53:44	1.9
+++ arch/parisc/kernel/processor.c	2002/04/05 07:43:12
@@ -187,6 +187,10 @@ void __init collect_boot_cpu_data(void)
 			boot_cpu_data.pdc.cpuid & 31,
 			boot_cpu_data.pdc.cpuid);
 
+	if (pdc_model_capabilities(&boot_cpu_data.pdc.capabilities) == PDC_OK)
+		printk(KERN_INFO "capabilities 0x%lx\n",
+			boot_cpu_data.pdc.capabilities);
+
 	if (pdc_model_sysmodel(boot_cpu_data.pdc.sys_model_name) == PDC_OK)
 		printk(KERN_INFO "model %s\n",
 			boot_cpu_data.pdc.sys_model_name);
Index: arch/parisc/kernel/sba_iommu.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/sba_iommu.c,v
retrieving revision 1.65
diff -u -p -r1.65 sba_iommu.c
--- arch/parisc/kernel/sba_iommu.c	2002/03/07 21:13:11	1.65
+++ arch/parisc/kernel/sba_iommu.c	2002/04/05 07:43:13
@@ -123,9 +123,11 @@
 #define IKE_IOC_OFFSET(p) ((p+2)*SBA_FUNC_SIZE)
 
 #define IOC_CTRL          0x8	/* IOC_CTRL offset */
-#define IOC_CTRL_TE       (0x1 << 0) /* TOC Enable */
-#define IOC_CTRL_RM       (0x1 << 8) /* Real Mode */
-#define IOC_CTRL_NC       (0x1 << 9) /* Non Coherent Mode */
+#define IOC_CTRL_TC       (1 << 0) /* TOC Enable */
+#define IOC_CTRL_CE       (1 << 1) /* Coalesce Enable */
+#define IOC_CTRL_DE       (1 << 2) /* Dillon Enable */
+#define IOC_CTRL_RM       (1 << 8) /* Real Mode */
+#define IOC_CTRL_NC       (1 << 9) /* Non Coherent Mode */
 
 #define MAX_IOC		2	/* per Ike. Astro only has 1 */
 
@@ -252,11 +254,16 @@ struct sba_device {
 
 
 static struct sba_device *sba_list;
-static int sba_count;
 
 /* Ratio of Host MEM to IOV Space size */
-static unsigned long sba_mem_ratio = 4;
+static unsigned long sba_mem_ratio = 8;
 
+/* global count of IOMMUs in the system */
+static unsigned int global_ioc_cnt = 0;
+
+/* PA8700 (Piranha 2.2) bug workaround */
+static unsigned long piranha_bad_128k = 0;
+
 /* Looks nice and keeps the compiler happy */
 #define SBA_DEV(d) ((struct sba_device *) (d))
 
@@ -297,16 +304,16 @@ static unsigned long sba_mem_ratio = 4;
  * IO Adapter (aka Bus Converter).
  */
 static void
-sba_dump_ranges(char *hpa)
+sba_dump_ranges(unsigned long hpa)
 {
-	DBG_INIT("SBA at 0x%p\n", hpa);
-	DBG_INIT("IOS_DIST_BASE   : %016lx\n", READ_REG64(hpa+IOS_DIST_BASE));
-	DBG_INIT("IOS_DIST_MASK   : %016lx\n", READ_REG64(hpa+IOS_DIST_MASK));
-	DBG_INIT("IOS_DIST_ROUTE  : %016lx\n", READ_REG64(hpa+IOS_DIST_ROUTE));
+	DBG_INIT("SBA at 0x%lx\n", hpa);
+	DBG_INIT("IOS_DIST_BASE   : %Lx\n", READ_REG64(hpa+IOS_DIST_BASE));
+	DBG_INIT("IOS_DIST_MASK   : %Lx\n", READ_REG64(hpa+IOS_DIST_MASK));
+	DBG_INIT("IOS_DIST_ROUTE  : %Lx\n", READ_REG64(hpa+IOS_DIST_ROUTE));
 	DBG_INIT("\n");
-	DBG_INIT("IOS_DIRECT_BASE : %016lx\n", READ_REG64(hpa+IOS_DIRECT_BASE));
-	DBG_INIT("IOS_DIRECT_MASK : %016lx\n", READ_REG64(hpa+IOS_DIRECT_MASK));
-	DBG_INIT("IOS_DIRECT_ROUTE: %016lx\n", READ_REG64(hpa+IOS_DIRECT_ROUTE));
+	DBG_INIT("IOS_DIRECT_BASE : %Lx\n", READ_REG64(hpa+IOS_DIRECT_BASE));
+	DBG_INIT("IOS_DIRECT_MASK : %Lx\n", READ_REG64(hpa+IOS_DIRECT_MASK));
+	DBG_INIT("IOS_DIRECT_ROUTE: %Lx\n", READ_REG64(hpa+IOS_DIRECT_ROUTE));
 }
 
 /**
@@ -316,13 +323,13 @@ sba_dump_ranges(char *hpa)
  * Print the size/location of the IO MMU PDIR.
  */
 static void
-sba_dump_tlb(char *hpa)
+sba_dump_tlb(unsigned long hpa)
 {
-	DBG_INIT("IO TLB at 0x%p\n", hpa);
-	DBG_INIT("IOC_IBASE    : %016lx\n", READ_REG64(hpa+IOC_IBASE));
-	DBG_INIT("IOC_IMASK    : %016lx\n", READ_REG64(hpa+IOC_IMASK));
-	DBG_INIT("IOC_TCNFG    : %016lx\n", READ_REG64(hpa+IOC_TCNFG));
-	DBG_INIT("IOC_PDIR_BASE: %016lx\n", READ_REG64(hpa+IOC_PDIR_BASE));
+	DBG_INIT("IO TLB at 0x%lx\n", hpa);
+	DBG_INIT("IOC_IBASE    : %Lx\n", READ_REG64(hpa+IOC_IBASE));
+	DBG_INIT("IOC_IMASK    : %Lx\n", READ_REG64(hpa+IOC_IMASK));
+	DBG_INIT("IOC_TCNFG    : %Lx\n", READ_REG64(hpa+IOC_TCNFG));
+	DBG_INIT("IOC_PDIR_BASE: %Lx\n", READ_REG64(hpa+IOC_PDIR_BASE));
 	DBG_INIT("\n");
 }
 #endif
@@ -726,7 +733,7 @@ sba_mark_invalid(struct ioc *ioc, dma_ad
 	u32 iovp = (u32) SBA_IOVP(ioc,iova);
 
 	/* Even though this is a big-endian machine, the entries
-	** in the iopdir are swapped. That's why we clear the byte
+	** in the iopdir are little endian. That's why we clear the byte
 	** at +7 instead of at +0.
 	*/
 	int off = PDIR_INDEX(iovp)*sizeof(u64)+7;
@@ -1421,6 +1428,102 @@ PAT_MOD(mod)->mod_info.ioc         = PAT
 *   Initialization and claim
 *
 ***************************************************************/
+#define PIRANHA_ADDR_MASK	0x00160000UL /* bit 17,18,20 */
+#define PIRANHA_ADDR_VAL	0x00060000UL /* bit 17,18 on */
+static void *
+sba_alloc_pdir(unsigned int pdir_size)
+{
+        unsigned long pdir_base;
+	unsigned long pdir_order = get_order(pdir_size);
+
+	pdir_base = __get_free_pages(GFP_KERNEL, pdir_order);
+	if (NULL == (void *) pdir_base)
+		panic("sba_ioc_init() could not allocate I/O Page Table\n");
+
+	/* If this is not PA8700 (PCX-W2)
+	**	OR newer than ver 2.2
+	**	OR in a system that doesn't need VINDEX bits from SBA,
+	**
+	** then we aren't exposed to the HW bug.
+	*/
+	if ( ((boot_cpu_data.pdc.cpuid >> 5) & 0x7f) != 0x13
+			|| (boot_cpu_data.pdc.versions > 0x202)
+			|| (boot_cpu_data.pdc.capabilities & 0x08L) )
+		return (void *) pdir_base;
+
+	/*
+	 * PA8700 (PCX-W2, aka piranha) silent data corruption fix
+	 *
+	 * An interaction between PA8700 CPU (Ver 2.2 or older) and
+	 * Ike/Astro can cause silent data corruption. This is only
+	 * a problem if the I/O PDIR is located in memory such that
+	 * (little-endian)  bits 17 and 18 are on and bit 20 is off.
+	 *
+	 * Since the max IO Pdir size is 2MB, by cleverly allocating the
+	 * right physical address, we can either avoid (IOPDIR <= 1MB)
+	 * or minimize (2MB IO Pdir) the problem if we restrict the
+	 * IO Pdir to a maximum size of 2MB-128K (1902K).
+	 *
+	 * Because we always allocate 2^N sized IO pdirs, either of the
+	 * "bad" regions will be the last 128K if at all. That's easy
+	 * to test for.
+	 * 
+	 */
+	if (pdir_order <= (19-12)) {
+		if (((virt_to_phys(pdir_base)+pdir_size-1) & PIRANHA_ADDR_MASK) == PIRANHA_ADDR_VAL) {
+			/* allocate a new one on 512k alignment */
+			unsigned long new_pdir = __get_free_pages(GFP_KERNEL, (19-12));
+			/* release original */
+			free_pages(pdir_base, pdir_order);
+
+			pdir_base = new_pdir;
+
+			/* release excess */
+			while (pdir_order < (19-12)) {
+				new_pdir += pdir_size;
+				free_pages(new_pdir, pdir_order);
+				pdir_order +=1;
+				pdir_size <<=1;
+			}
+		}
+	} else {
+		/*
+		** 1MB or 2MB Pdir
+		** Needs to be aligned on an "odd" 1MB boundary.
+		*/
+		unsigned long new_pdir = __get_free_pages(GFP_KERNEL, pdir_order+1); /* 2 or 4MB */
+
+		/* release original */
+		free_pages( pdir_base, pdir_order);
+
+		/* release first 1MB */
+		free_pages(new_pdir, 20-12);
+
+		pdir_base = new_pdir + 1024*1024;
+
+		if (pdir_order > (20-12)) {
+			/*
+			** 2MB Pdir.
+			**
+			** Flag tells init_bitmap() to mark bad 128k as used
+			** and to reduce the size by 128k.
+			*/
+			piranha_bad_128k = 1;
+
+			new_pdir += 3*1024*1024;
+			/* release last 1MB */
+			free_pages(new_pdir, 20-12);
+
+			/* release unusable 128KB */
+			free_pages(new_pdir - 128*1024 , 17-12);
+
+			pdir_size -= 128*1024;
+		}
+	}
+
+	memset((void *) pdir_base, 0, pdir_size);
+	return (void *) pdir_base;
+}
 
 
 static void
@@ -1430,7 +1533,6 @@ sba_ioc_init(struct parisc_device *sba, 
 	extern void lba_set_iregs(struct parisc_device *, u32, u32);
 
 	u32 iova_space_size, iova_space_mask;
-	void * pdir_base;
 	int pdir_size, iov_order;
 	unsigned long physmem;
 	struct parisc_device *lba;
@@ -1448,22 +1550,24 @@ sba_ioc_init(struct parisc_device *sba, 
 	** While we have 32-bits "IOVA" space, top two 2 bits are used
 	** for DMA hints - ergo only 30 bits max.
 	*/
-	/* limit IOVA space size to 1MB-1GB */
 
 	physmem = num_physpages << PAGE_SHIFT;
-	if (physmem < (sba_mem_ratio*1024*1024)) {
+	iova_space_size = (u32) (physmem/(sba_mem_ratio*global_ioc_cnt));
+
+	/* limit IOVA space size to 1MB-1GB */
+	if (iova_space_size < 1024*1024) {
 		iova_space_size = 1024*1024;
+	}
 #ifdef __LP64__
-	} else if (physmem > (sba_mem_ratio*512*1024*1024)) {
+	else if (iova_space_size > 512*1024*1024) {
 		iova_space_size = 512*1024*1024;
-#endif
-	} else {
-		iova_space_size = (u32) (physmem/sba_mem_ratio);
 	}
+#endif
 
 	/*
 	** iova space must be log2() in size.
 	** thus, pdir/res_map will also be log2().
+	** PIRANHA BUG: Exception is when IO Pdir is 2MB (gets reduced)
 	*/
 	iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
 	ASSERT(iov_order <= (30 - IOVP_SHIFT));   /* iova_space_size <= 1GB */
@@ -1472,12 +1576,12 @@ sba_ioc_init(struct parisc_device *sba, 
 
 	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
 
-	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size < 4MB */
+	ASSERT(pdir_size < 4*1024*1024);   /* max pdir size == 2MB */
 
 	/* Verify it's a power of two */
 	ASSERT((1 << get_order(pdir_size)) == (pdir_size >> PAGE_SHIFT));
 
-	DBG_INIT("%s() hpa 0x%p mem %dMB IOV %dMB (%d bits) PDIR size 0x%0x\n",
+	DBG_INIT("%s() hpa 0x%lx mem %dMB IOV %dMB (%d bits) PDIR size 0x%0x\n",
 		__FUNCTION__, ioc->ioc_hpa, (int) (physmem>>20),
 		iova_space_size>>20, iov_order + PAGE_SHIFT, pdir_size);
 
@@ -1485,22 +1589,14 @@ sba_ioc_init(struct parisc_device *sba, 
 	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
 	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
 
-	ioc->pdir_base =
-	pdir_base = (void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
-	if (NULL == pdir_base)
-	{
-		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
-	}
-	memset(pdir_base, 0, pdir_size);
+	ioc->pdir_base = sba_alloc_pdir(pdir_size);
 
 	DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
-		__FUNCTION__, pdir_base, pdir_size,
+		__FUNCTION__, ioc->pdir_base, pdir_size,
 		ioc->hint_shift_pdir, ioc->hint_mask_pdir);
-
-	ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
-	WRITE_REG64(virt_to_phys(pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
 
-	DBG_INIT(" base %p\n", pdir_base);
+	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+	WRITE_REG64(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
 
 	/* build IMASK for IOC and Elroy */
 	iova_space_mask =  0xffffffff;
@@ -1570,16 +1666,16 @@ sba_hw_init(struct sba_device *sba_dev)
 	u64 ioc_ctl;
 
 	ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
-	DBG_INIT("%s() hpa 0x%p ioc_ctl 0x%016lx ->",
+	DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
 		__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
-	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC);
-	ASSERT(ioc_ctl & IOC_CTRL_TE);	/* astro: firmware enables this */
+	ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE);
+	ioc_ctl |= IOC_CTRL_TC;	/* Astro: firmware enables this */
 
 	WRITE_REG(ioc_ctl, sba_dev->sba_hpa+IOC_CTRL);
 
 #ifdef DEBUG_SBA_INIT
-	ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
-	DBG_INIT(" 0x%016lx\n", ioc_ctl);
+	ioc_ctl = READ_REG64(sba_dev->sba_hpa+IOC_CTRL);
+	DBG_INIT(" 0x%Lx\n", ioc_ctl);
 #endif
 
 	if (IS_ASTRO(sba_dev->iodc)) {
@@ -1624,7 +1720,6 @@ sba_common_init(struct sba_device *sba_d
 	*/
 	sba_dev->next = sba_list;
 	sba_list = sba_dev;
-	sba_count++;
 
 	for(i=0; i< sba_dev->num_ioc; i++) {
 		int res_size;
@@ -1636,6 +1731,12 @@ sba_common_init(struct sba_device *sba_d
 #endif
 		/* resource map size dictated by pdir_size */
 		res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
+
+		/* Second part of PIRANHA BUG */
+		if (piranha_bad_128k) {
+			res_size -= (128*1024)/sizeof(u64);
+		}
+
 		res_size >>= 3;  /* convert bit count to byte count */
 		DBG_INIT("%s() res_size 0x%x\n",
 			__FUNCTION__, res_size);
@@ -1664,6 +1765,21 @@ sba_common_init(struct sba_device *sba_d
 		sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL;
 #endif
 
+		/* Third (and last) part of PIRANHA BUG */
+		if (piranha_bad_128k) {
+			/* region from +1408K to +1536 is un-usable. */
+
+			int idx_start = (1408*1024/sizeof(u64)) >> 3;
+			int idx_end   = (1536*1024/sizeof(u64)) >> 3;
+			long *p_start = (long *) &(sba_dev->ioc[i].res_map[idx_start]);
+			long *p_end   = (long *) &(sba_dev->ioc[i].res_map[idx_end]);
+
+			/* mark that part of the io pdir busy */
+			while (p_start < p_end)
+				*p_start++ = -1;
+				
+		}
+
 #ifdef DEBUG_DMB_TRAP
 		iterate_pages( sba_dev->ioc[i].res_map, res_size,
 				set_data_memory_break, 0);
@@ -1735,6 +1851,8 @@ static int sba_proc_info(char *buf, char
 	return strlen(buf);
 }
 
+#if 0
+/* XXX too much output - exceeds 4k limit and needs to be re-written */
 static int
 sba_resource_map(char *buf, char **start, off_t offset, int len)
 {
@@ -1753,8 +1871,31 @@ sba_resource_map(char *buf, char **start
 
 	return strlen(buf);
 }
-#endif
+#endif /* 0 */
+#endif /* CONFIG_PROC_FS */
 
+static struct parisc_device_id sba_tbl[] = {
+	{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
+	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc },
+/* These two entries commented out because we don't find them in a
+ * buswalk yet.  If/when we do, they would cause us to think we had
+ * many more SBAs then we really do.
+ *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xc },
+ *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xc },
+ */
+	{ 0, }
+};
+
+int sba_driver_callback(struct parisc_device *);
+
+static struct parisc_driver sba_driver = {
+	name:		MODULE_NAME,
+	id_table:	sba_tbl,
+	probe:		sba_driver_callback,
+};
+
 /*
 ** Determine if lba should claim this chip (return 0) or not (return 1).
 ** If so, initialize the chip and tell other partners in crime they
@@ -1772,36 +1913,47 @@ sba_driver_callback(struct parisc_device
 	sba_dump_ranges(dev->hpa);
 #endif
 
+	/* Read HW Rev First */
+	func_class = READ_REG(dev->hpa + SBA_FCLASS);
+
 	if (IS_ASTRO(&dev->id)) {
+		unsigned long fclass;
 		static char astro_rev[]="Astro ?.?";
 
-		/* Read HW Rev First */
-		func_class = READ_REG(dev->hpa);
+		/* Astro is broken...Read HW Rev First */
+		fclass = READ_REG(dev->hpa);
 
-		astro_rev[6] = '1' + (char) (func_class & 0x7);
-		astro_rev[8] = '0' + (char) ((func_class & 0x18) >> 3);
+		astro_rev[6] = '1' + (char) (fclass & 0x7);
+		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
 		version = astro_rev;
+
 	} else if (IS_IKE(&dev->id)) {
 		static char ike_rev[]="Ike rev ?";
 
-		/* Read HW Rev First */
-		func_class = READ_REG(dev->hpa + SBA_FCLASS);
-
 		ike_rev[8] = '0' + (char) (func_class & 0xff);
 		version = ike_rev;
 	} else {
 		static char reo_rev[]="REO rev ?";
 
-		/* Read HW Rev First */
-		func_class = READ_REG(dev->hpa + SBA_FCLASS);
-
 		reo_rev[8] = '0' + (char) (func_class & 0xff);
 		version = reo_rev;
 	}
 
+	if (!global_ioc_cnt) {
+		global_ioc_cnt = count_parisc_driver(&sba_driver);
+
+		/* Only Astro has one IOC per SBA */
+		if (!IS_ASTRO(&dev->id))
+			global_ioc_cnt *= 2;
+	}
+
 	printk(KERN_INFO "%s found %s at 0x%lx\n",
 		MODULE_NAME, version, dev->hpa);
 
+#ifdef DEBUG_SBA_INIT
+	sba_dump_tlb(dev->hpa);
+#endif
+
 	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
 	if (NULL == sba_dev) {
 		printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
@@ -1834,30 +1986,12 @@ sba_driver_callback(struct parisc_device
 	} else {
 		create_proc_info_entry("Reo", 0, proc_runway_root, sba_proc_info);
 	}
+#if 0
 	create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map);
 #endif
+#endif
 	return 0;
 }
-
-static struct parisc_device_id sba_tbl[] = {
-	{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },
-	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc },
-	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
-	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REOG_MERCED_PORT, 0xc },
-/* These two entries commented out because we don't find them in a
- * buswalk yet.  If/when we do, they would cause us to think we had
- * many more SBAs then we really do.
- *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, ASTRO_ROPES_PORT, 0xc },
- *	{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_ROPES_PORT, 0xc },
- */
-	{ 0, }
-};
-
-static struct parisc_driver sba_driver = {
-	name:		MODULE_NAME,
-	id_table:	sba_tbl,
-	probe:		sba_driver_callback,
-};
 
 /*
 ** One time initialization to let the world know the SBA was found.
Index: include/asm-parisc/hardware.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/hardware.h,v
retrieving revision 1.36
diff -u -p -r1.36 hardware.h
--- include/asm-parisc/hardware.h	2002/02/28 07:11:20	1.36
+++ include/asm-parisc/hardware.h	2002/04/05 07:43:17
@@ -139,6 +139,7 @@ extern struct parisc_device *alloc_pa_de
 		struct hardware_path *path);
 extern int register_parisc_device(struct parisc_device *dev);
 extern int register_parisc_driver(struct parisc_driver *driver);
+extern int count_parisc_driver(struct parisc_driver *driver);
 extern int unregister_parisc_driver(struct parisc_driver *driver);
 extern void walk_central_bus(void);
 extern void fixup_child_irqs(struct parisc_device *parent, int irqbase,
Index: include/asm-parisc/io.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/io.h,v
retrieving revision 1.27
diff -u -p -r1.27 io.h
--- include/asm-parisc/io.h	2002/02/25 23:06:48	1.27
+++ include/asm-parisc/io.h	2002/04/05 07:43:17
@@ -92,7 +92,7 @@ extern __inline__ unsigned long long __r
 	:  "=r" (ret) : "r" (addr) );
 #else
 	/* two reads may have side effects.. */
-	ret = (unsigned long long) __raw_readl(addr) << 32;
+	ret = ((u64) __raw_readl(addr)) << 32;
 	ret |= __raw_readl(addr+4);
 #endif
 	return ret;
@@ -142,16 +142,20 @@ extern __inline__ void __raw_writeq(unsi
 #define readb(addr) (*(volatile unsigned char *) (addr))
 #define readw(addr) (*(volatile unsigned short *) (addr))
 #define readl(addr) (*(volatile unsigned int *) (addr))
+#define readq(addr) (*(volatile u64 *) (addr))
 #define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
 #define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
 #define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
+#define writeq(b,addr) (*(volatile u64 *) (addr) = (b))
 #else /* !USE_HPPA_IOREMAP */
-#define readb(addr) __raw_readb((unsigned long)addr)
-#define readw(addr) le16_to_cpu(__raw_readw((unsigned long)addr))
-#define readl(addr) le32_to_cpu(__raw_readl((unsigned long)addr))
-#define writeb(b,addr) __raw_writeb(b,(unsigned long)addr)
-#define writew(b,addr) __raw_writew(cpu_to_le16(b),(unsigned long)addr)
-#define writel(b,addr) __raw_writel(cpu_to_le32(b),(unsigned long)addr)
+#define readb(addr) __raw_readb((unsigned long)(addr))
+#define readw(addr) le16_to_cpu(__raw_readw((unsigned long)(addr)))
+#define readl(addr) le32_to_cpu(__raw_readl((unsigned long)(addr)))
+#define readq(addr) le64_to_cpu(__raw_readq((unsigned long)(addr)))
+#define writeb(b,addr) __raw_writeb(b,(unsigned long)(addr))
+#define writew(b,addr) __raw_writew(cpu_to_le16(b),(unsigned long)(addr))
+#define writel(b,addr) __raw_writel(cpu_to_le32(b),(unsigned long)(addr))
+#define writeq(b,addr) __raw_writeq(cpu_to_le64(b),(unsigned long)(addr))
 #endif /* !USE_HPPA_IOREMAP */
 
 extern void memcpy_fromio(void *dest, unsigned long src, int count);
Index: include/asm-parisc/processor.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/processor.h,v
retrieving revision 1.52
diff -u -p -r1.52 processor.h
--- include/asm-parisc/processor.h	2001/11/10 00:10:49	1.52
+++ include/asm-parisc/processor.h	2002/04/05 07:43:17
@@ -57,6 +57,7 @@ struct system_cpuinfo_parisc {
 		struct pdc_model model;
 		unsigned long versions;
 		unsigned long cpuid;
+		unsigned long capabilities;
 		char   sys_model_name[81]; /* PDC-ROM returnes this model name */
 	} pdc;