+static void
+sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
+{
+ /* lba_set_iregs() is in arch/parisc/kernel/lba_pci.c */
+ extern void lba_set_iregs(struct parisc_device *, u32, u32);
+
+ u32 iova_space_mask;
+ u32 iova_space_size;
+ int iov_order, tcnfg;
+ struct parisc_device *lba;
+#if SBA_AGP_SUPPORT
+ int agp_found = 0;
+#endif
+ /*
+ ** Firmware programs the base and size of a "safe IOVA space"
+ ** (one that doesn't overlap memory or LMMIO space) in the
+ ** IBASE and IMASK registers.
+ */
+ ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE);
+ iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
+
+ if ((ioc->ibase < 0xfed00000UL) && ((ioc->ibase + iova_space_size) > 0xfee00000UL)) {
+ printk("WARNING: IOV space overlaps local config and interrupt message, truncating\n");
+ iova_space_size /= 2;
+ }
+
+ /*
+ ** iov_order is always based on a 1GB IOVA space since we want to
+ ** turn on the other half for AGP GART.
+ */
+ iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
+ ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
+
+ DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",
+ __FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
+ iov_order + PAGE_SHIFT);
+
+ ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL,
+ get_order(ioc->pdir_size));
+ if (!ioc->pdir_base)
+ panic("Couldn't allocate I/O Page Table\n");
+
+ memset(ioc->pdir_base, 0, ioc->pdir_size);
+
+ DBG_INIT("%s() pdir %p size %x\n",
+ __FUNCTION__, ioc->pdir_base, ioc->pdir_size);
+
+#if SBA_HINT_SUPPORT
+ ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
+ ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
+
+ DBG_INIT(" hint_shift_pdir %x hint_mask_pdir %lx\n",
+ ioc->hint_shift_pdir, ioc->hint_mask_pdir);
+#endif
+
+ ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+ WRITE_REG(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
+
+ /* build IMASK for IOC and Elroy */
+ iova_space_mask = 0xffffffff;
+ iova_space_mask <<= (iov_order + PAGE_SHIFT);
+ ioc->imask = iova_space_mask;
+#ifdef ZX1_SUPPORT
+ ioc->iovp_mask = ~(iova_space_mask + PAGE_SIZE - 1);
+#endif
+ sba_dump_tlb(ioc->ioc_hpa);
+
+ /*
+ ** setup Mercury IBASE/IMASK registers as well.
+ */
+ for (lba = sba->child; lba; lba = lba->sibling) {
+ int rope_num = (lba->hpa >> 13) & 0xf;
+ if (rope_num >> 3 == ioc_num)
+ lba_set_iregs(lba, ioc->ibase, ioc->imask);
+ }
+
+ WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK);
+
+#ifdef __LP64__
+ /*
+ ** Setting the upper bits makes checking for bypass addresses
+ ** a little faster later on.
+ */
+ ioc->imask |= 0xFFFFFFFF00000000UL;
+#endif
+
+ /* Set I/O PDIR Page size to system page size */
+ switch (PAGE_SHIFT) {
+ case 12: tcnfg = 0; break; /* 4K */
+ case 13: tcnfg = 1; break; /* 8K */
+ case 14: tcnfg = 2; break; /* 16K */
+ case 16: tcnfg = 3; break; /* 64K */
+ default:
+ panic(__FILE__ "Unsupported system page size %d",
+ 1 << PAGE_SHIFT);
+ break;
+ }
+ WRITE_REG(tcnfg, ioc->ioc_hpa + IOC_TCNFG);
+
+ /*
+ ** Program the IOC's ibase and enable IOVA translation
+ ** Bit zero == enable bit.
+ */
+ WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE);
+
+ /*
+ ** Clear I/O TLB of any possible entries.
+ ** (Yes. This is a bit paranoid...but so what)
+ */
+ WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
+
+#if SBA_AGP_SUPPORT
+ /*
+ ** If an AGP device is present, only use half of the IOV space
+ ** for PCI DMA. Unfortunately we can't know ahead of time
+ ** whether GART support will actually be used, for now we
+ ** can just key on any AGP device found in the system.
+ ** We program the next pdir index after we stop w/ a key for
+ ** the GART code to handshake on.
+ */
+ device=NULL;
+ for (lba = sba->child; lba; lba = lba->sibling) {
+ if (IS_QUICKSILVER(lba))
+ break;
+ }
+
+ if (lba) {
+ DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
+ ioc->pdir_size /= 2;
+ ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
+ } else {
+ DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
+ }
+#endif /* 0 */
+
+}